home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / smaltalk / gnu_st.lha / gnu_st / smalltalk-1.1.1 / mstcomp.c < prev    next >
C/C++ Source or Header  |  1991-09-12  |  77KB  |  2,923 lines

  1. /***********************************************************************
  2.  *
  3.  *    Byte code compiler.
  4.  *
  5.  ***********************************************************************/
  6.  
  7. /***********************************************************************
  8.  *
  9.  * Copyright (C) 1990, 1991 Free Software Foundation, Inc.
  10.  * Written by Steve Byrne.
  11.  *
  12.  * This file is part of GNU Smalltalk.
  13.  *
  14.  * GNU Smalltalk is free software; you can redistribute it and/or modify it
  15.  * under the terms of the GNU General Public License as published by the Free
  16.  * Software Foundation; either version 1, or (at your option) any later 
  17.  * version.
  18.  * 
  19.  * GNU Smalltalk is distributed in the hope that it will be useful, but WITHOUT
  20.  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
  21.  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  22.  * more details.
  23.  * 
  24.  * You should have received a copy of the GNU General Public License along with
  25.  * GNU Smalltalk; see the file COPYING.  If not, write to the Free Software
  26.  * Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  
  27.  *
  28.  ***********************************************************************/
  29.  
  30.  
  31. /*
  32.  *    Change Log
  33.  * ============================================================================
  34.  * Author      Date       Change 
  35.  * sbb         12 Sep 91      Fixed equalConstant to not poop out on recursive
  36.  *              array constants.
  37.  *
  38.  * sbb         12 Sep 91      Fixed duplicated time declaration code in
  39.  *              executeStatements.
  40.  *
  41.  * sbyrne    20 May 90      Improved error handling...compiler errors set a flag,
  42.  *              and execution does not occur if the expression to be
  43.  *              executed has compilation errors.
  44.  *
  45.  * sbyrne    16 May 90      Added usage of emacsProcess.
  46.  *
  47.  * sbyrne    20 Apr 90      Fixed compiler to reset the byte code system before
  48.  *              using it.  The problem was if an error occurred, the
  49.  *              old byte code stream was still in use, and further
  50.  *              compilations were losing in a big way.
  51.  *
  52.  * sbyrne    25 Mar 90      Changed cache hit ratio reporting to check for divide
  53.  *              by zero, and to cast the byte counter to double (it
  54.  *              was casting to float and relying on promotion).
  55.  *
  56.  * sbyrne    13 Jan 90      Added support for "thisContext" as a compiler
  57.  *              built-in variable.
  58.  *
  59.  * sbyrne    28 Dec 89      Compiled methods now record their exact number of
  60.  *              byte codes.  Previously, if the byte codes didn't
  61.  *              exactly fill to a word-boundary, there was no way to
  62.  *              distinguish that case.  Now, with the advent of
  63.  *              dumping byte codes from within Smalltalk, this has
  64.  *              become a necessity.
  65.  *
  66.  * sbyrne    27 Dec 89      Realloc literal vec wasn't reallocing in units of
  67.  *              sizeof(OOP), so after a while, the literal vector
  68.  *              wasn't big enough.  Typically most methods don't have
  69.  *              a lot of literals, so this was not a problem.
  70.  *
  71.  * sbyrne     2 Oct 89      Fixed a bug with compilation of cascaded messages.
  72.  *              see HACK ALERT below.
  73.  *
  74.  * sbyrne    21 Sep 89      Made compilation of methods from strings record the
  75.  *              source string.
  76.  *
  77.  * sbyrne    13 Sep 89      Various changes for garbage collector.
  78.  *
  79.  * sbyrne     2 Sep 89      Began adding support for the method descriptor
  80.  *              instance variable.
  81.  *
  82.  * sbyrne     2 Jan 89      I guess it should be stated somewhere: you'll notice
  83.  *              in the code that there are several places where I
  84.  *              could have taken a more "functional" (i.e. LISP
  85.  *              oriented call a function within a function call)
  86.  *              approach.  I chose not to because it can make
  87.  *              debugging easier, it doesn't slow down the code much,
  88.  *              and may help the reader to understand better what's
  89.  *              going on in the code.
  90.  *
  91.  * sbyrne     1 Jan 89      Created.
  92.  *
  93.  */
  94.  
  95.  
  96. #include "mst.h"
  97. #include "mstsym.h"
  98. #include "mstcomp.h"
  99. #include "msttree.h"
  100. #include "mstbyte.h"
  101. #include "mstdict.h"
  102. #include "mstoop.h"
  103. #include "mstinterp.h"
  104. #include "mstlex.h"
  105. #include <setjmp.h>
  106. #ifdef HAS_ALLOCA_H
  107. #include <alloca.h>
  108. #endif
  109. #include <sys/time.h>
  110. #if defined(USG)
  111. #include <sys/times.h>
  112. #endif
  113.  
  114. #define LITERAL_VEC_CHUNK_SIZE        32
  115.  
  116. extern    long        cacheHits, cacheMisses;
  117.  
  118. typedef enum {
  119.   falseJump,
  120.   trueJump,
  121.   unconditionalJump
  122. } JumpType;
  123.  
  124. typedef enum {
  125.   methodContext,
  126.   blockContext
  127. } ContextType;
  128.  
  129. typedef struct CompiledMethodStruct *CompiledMethod;
  130.  
  131. typedef struct MethodInfoStruct {
  132.   OBJ_HEADER;
  133.   OOP        sourceCode;
  134.   OOP        category;
  135. } *MethodInfo;
  136.  
  137. typedef struct FileSegmentStruct {
  138.   OBJ_HEADER;
  139.   OOP        fileName;
  140.   OOP        startPos;
  141.   OOP        length;
  142. } *FileSegment;
  143.  
  144. /* These hold the compiler's notions of the current class for compilations,
  145.  * and the current category that compiled methods are to be placed into */
  146. OOP            thisClass, thisCategory;
  147.  
  148. /* These flags control whether byte codes are printed after compilation,
  149.  * and whether regression testing is in effect (which causes any messages
  150.  * that the system prints out to become constant messages, i.e. no timing
  151.  * information is printed) */
  152. Boolean            declareTracing, regressionTesting;
  153.  
  154. /* If true, the normal execution information is supressed, and the prompt
  155.  * is emitted with a special marker character ahead of it to let the process
  156.  * filter know that the execution has completed. */
  157. Boolean                   emacsProcess = false;
  158.  
  159. static Boolean        hasExtendedSuper, isSuper(), equalConstant(),
  160.               compileWhileLoop(), compileIfStatement(),
  161.             compileIfTrueFalseStatement(), compileAndOrStatement();
  162. static OOP        computeSelector(), makeConstantOOP(),
  163.               getMethodLiterals(), makeNewMethod(), methodNew(),
  164.             methodInfoNew(), fileSegmentNew();
  165. static ByteCodes    optimizeByteCodes(), compileSubExpression(),
  166.               compileSubExpressionWithGoto(),
  167.               compileDefaultValue();
  168. static int        computeLocationIndex(), isSpecialVariable(),
  169.             addConstant(), addSelector(), whichBuiltinSelector(),
  170.             addForcedSelector(), listLength(), addLiteral();
  171. static CompiledMethod    simpleMethodNew();
  172. static void         compileStatement(), compileExpression(),
  173.               compileSimpleExpression(), compileVariable(),
  174.               compileConstant(), compileBlock(),
  175.               compileStatements(), compileUnaryExpr(),
  176.               compileBinaryExpr(), compileKeywordExpr(),
  177.               compileSend(), compileCascadedMessage(),
  178.               compileAssignments(), addMethodClassVariable(),
  179.               compileJump(), compileKeywordList(),
  180.               initLiteralVec(), reallocLiteralVec(),
  181.               compileBlockArguments(), installMethod();
  182.  
  183. /* Used to abort really losing compiles, jumps back to the top level of the
  184.  * compiler */
  185. static jmp_buf        badMethod;
  186.  
  187. /* The vector of literals that the compiler uses to accumulate literal
  188.  * constants into */
  189. static OOP        *literalVec;
  190.  
  191. /* These indicate the current number of literals in the method being compiled
  192.  * and the current maximum allocated size of the literal vector */
  193. static int        numLiterals, literalVecMax;
  194.  
  195. /* HACK ALERT!! HACK ALERT!!  This variable is used for cascading.  The
  196.  * tree structure is all wrong for the code in cascade processing to find
  197.  * the receiver of the initial message.  What this does is when it's true,
  198.  * compileUnaryExpr, compileBinaryExpr, and compileKeywordExpr record
  199.  * its value, and clear the global (to prevent propagation to compilation
  200.  * of subnodes).  After compiling their receiver, if the saved value of
  201.  * the flag is true, they emit a dupStackTop, and continue compilation.
  202.  * Since cascaded sends are relatively rare, I figured that this was a better
  203.  * alternative than passing useless parameters around all the time.
  204.  */
  205. static Boolean        dupMessageReceiver = false;
  206.  
  207. /*
  208.  *    void installInitialMethods()
  209.  *
  210.  * Description
  211.  *
  212.  *    This routine does a very interesting thing.  It installs the inital
  213.  *    method, which is the primitive for "methodsFor:".  It does this by
  214.  *    creating a string that contains the method definition and then passing
  215.  *    this to the parser as an expression to be parsed and compiled.  Once
  216.  *    this has been installed, we can go ahead and begin loading the rest of
  217.  *    the Smalltalk method definitions, but until the "methodsFor:" method is
  218.  *    defined, we cannot begin to deal with
  219.  *    "!Object methodsFor: 'primitives'!".
  220.  *
  221.  */
  222. void installInitialMethods()
  223. {
  224.   char        *methodsForString;
  225.  
  226.   initDefaultCompilationEnvironment();
  227.  
  228.   methodsForString = "\
  229. methodsFor: aCategoryString \
  230.     <primitive: 150> \
  231. ";
  232.   initLexer(true);        /* tell the lexer we're doing internal
  233.                    compiles */
  234.  
  235.   pushSmalltalkString(stringNew(methodsForString));
  236.   yyparse();
  237.   popStream(false);        /* can't close a string! */
  238. }
  239.  
  240. /*
  241.  *    void initDefaultCompilationEnvironment()
  242.  *
  243.  * Description
  244.  *
  245.  *    Does what it says.
  246.  *
  247.  */
  248. void initDefaultCompilationEnvironment()
  249. {
  250.   setCompilationClass(behaviorClass);
  251.   setCompilationCategory(nilOOP);
  252. }
  253.  
  254. /*
  255.  *    void invokeInitBlocks()
  256.  *
  257.  * Description
  258.  *
  259.  *    This function will send a message to Smalltalk (the system dictionary)
  260.  *    asking it to invoke a set of initialization blocks.  There are methods
  261.  *    in Smalltalk that allow for the recording of blocks to be invoked after
  262.  *    image load, and this function sets that process in motion.
  263.  *
  264.  */
  265. void invokeInitBlocks()
  266. {
  267.   /* +++ this will eventually be replaced with the user-level callin */
  268.   prepareExecutionEnvironment();
  269.   pushOOP(smalltalkDictionary);
  270.   sendMessage(internString("doInits"), 0, false);
  271.   interpret();
  272.   finishExecutionEnvironment();
  273. }
  274.  
  275. /*
  276.  *    void setCompilationClass(classOOP)
  277.  *
  278.  * Description
  279.  *
  280.  *    Sets the compiler's notion of the class to compile methods into.
  281.  *
  282.  * Inputs
  283.  *
  284.  *    classOOP: 
  285.  *        An OOP for a Class object to compile method definitions into.
  286.  *
  287.  */
  288. void setCompilationClass(classOOP)
  289. OOP    classOOP;
  290. {
  291.   maybeMoveOOP(classOOP);
  292.   thisClass = classOOP;
  293. }
  294.  
  295. /*
  296.  *    void setCompilationCategory(categoryOOP)
  297.  *
  298.  * Description
  299.  *
  300.  *    Sets the compiler's notion of the current method category
  301.  *
  302.  * Inputs
  303.  *
  304.  *    categoryOOP: 
  305.  *        An OOP that indicates the category to be used.  Typically a
  306.  *        string.
  307.  *
  308.  */
  309. void setCompilationCategory(categoryOOP)
  310. OOP    categoryOOP;
  311. {
  312.   maybeMoveOOP(categoryOOP);
  313.   thisCategory = categoryOOP;
  314. }
  315.  
  316. /*
  317.  *    void copyCompileContext()
  318.  *
  319.  * Description
  320.  *
  321.  *    Called only during a GC flip, this routine copies the current
  322.  *    compilation context variables to new space, since they're part of the
  323.  *    "root set".
  324.  *
  325.  */
  326. void copyCompileContext()
  327. {
  328.   if (!isNil(thisClass)) {
  329.     maybeMoveOOP(thisClass);
  330.   }
  331.  
  332.   if (!isNil(thisCategory)) {
  333.     maybeMoveOOP(thisCategory);
  334.   }
  335. }
  336.  
  337. /*
  338.  *    void executeStatements(temporaries, statements, quiet)
  339.  *
  340.  * Description
  341.  *
  342.  *    Called to compile and execute an "immediate expression"; i.e. a set of
  343.  *    Smalltalk statements that are not part of a method definition.
  344.  *
  345.  * Inputs
  346.  *
  347.  *    temporaries: 
  348.  *        Syntax tree node that represents the temporary variables
  349.  *        associated with the expression.
  350.  *    statements: 
  351.  *        The statements of the expression.  A syntax tree node.
  352.  *    quiet : Flag to indicate either messages are to be output indicating
  353.  *        the commencement of execution and some timing results at the
  354.  *        end of execution.
  355.  *
  356.  */
  357. void executeStatements(temporaries, statements, quiet)
  358. TreeNode temporaries, statements;
  359. Boolean    quiet;
  360. {
  361.   TreeNode    messagePattern;
  362. #if !defined(USG)
  363.   struct timeval startTime, endTime, deltaTime;
  364. #else
  365.   time_t startTime, endTime, deltaTime;
  366.   struct tms dummy;
  367. #endif
  368.   OOP        returnedValue;
  369.  
  370.   setCompilationClass(objectClass);
  371.  
  372.   messagePattern = makeUnaryExpr(nil, "executeStatements");
  373.   compileMethod(makeMethod(messagePattern, temporaries, 0, statements), false);
  374.   if (hadError) {        /* don't execute on error */
  375.     return;
  376.   }
  377.  
  378.   /* send a message to NIL, which will find this synthetic method definition
  379.      in Object and execute it */
  380.   prepareExecutionEnvironment();
  381.   pushOOP(nilOOP);
  382.   if (!quiet) {
  383.     printf("\nExecution begins...\n");
  384.   }
  385.   sendMessage(internString("executeStatements"), 0, false);
  386.   byteCodeCounter = 0;
  387. #if !defined(USG)
  388.   gettimeofday(&startTime, nil);
  389.   interpret();
  390.   gettimeofday(&endTime, nil);
  391. #else
  392.   startTime = times(&dummy);
  393.   interpret();
  394.   endTime = times(&dummy);
  395. #endif
  396.   returnedValue = finishExecutionEnvironment();
  397.   if (!quiet) {
  398.     if (!regressionTesting) {
  399.       printf("%d byte codes executed\n", byteCodeCounter);
  400. #if !defined(USG)
  401.       deltaTime.tv_sec = endTime.tv_sec - startTime.tv_sec;
  402.       deltaTime.tv_usec = endTime.tv_usec - startTime.tv_usec;
  403.       if (deltaTime.tv_usec < 0) {
  404.     deltaTime.tv_sec--;
  405.     deltaTime.tv_usec += 1000000;
  406.       }
  407.       if (deltaTime.tv_sec == 0 && deltaTime.tv_usec == 0) {
  408.     deltaTime.tv_usec = 1;    /* fake a non-zero amount of time */
  409.       }
  410.       printf("which took %d.%d seconds, giving %f bytecodes/sec\n",
  411.          deltaTime.tv_sec, deltaTime.tv_usec, (double)byteCodeCounter/
  412.          (deltaTime.tv_sec + deltaTime.tv_usec/1000000.0));
  413. #else
  414.       deltaTime = endTime - startTime;
  415.       if (deltaTime <= 0){
  416.      deltaTime = 1;        /* it could be zero which would core dump */
  417.       }
  418.       printf("which took %d.%d seconds, giving %f bytecodes/sec\n",
  419.          deltaTime/gethz(), deltaTime%gethz(), (float)byteCodeCounter/
  420.          (deltaTime / (double) gethz()));
  421. #endif
  422.       if (cacheHits + cacheMisses) {
  423.     printf("%d cache hits, %d misses %f hit ratio\n",
  424.            cacheHits, cacheMisses,
  425.            (float)cacheHits / (cacheHits + cacheMisses));
  426.       } else {
  427.     printf("%d cache hits, %d misses\n",
  428.            cacheHits, cacheMisses);
  429.       }
  430.       
  431. /*    approx 25% of byte codes are sends
  432.       printf("sends / bytecodes = %.1f\n",
  433.          (cacheHits + cacheMisses) * 100.0 / byteCodeCounter );
  434. */
  435. #ifdef countingByteCodes 
  436.       printByteCodeCounts();
  437. #endif
  438. #ifdef collision_checking
  439.       { int i;
  440.     extern int collide[];
  441.     for (i = 0; i < 2048; i++) {
  442.       if (collide[i]) {
  443.         printf("collide[%d] = %d\n", i, collide[i]);
  444.       }
  445.     }
  446.       }
  447. #endif /* collision_checking */
  448.     }
  449.  
  450.     printf("returned value is ");
  451.     printObject(returnedValue);
  452.     printf("\n");
  453.   }
  454. }
  455.  
  456.  
  457. /*
  458.  *    void compileMethod(method)
  459.  *
  460.  * Description
  461.  *
  462.  *    Compile the code for a complete method definition.  Special cases for
  463.  *    methods that don't return a value explicitly by returning "self".
  464.  *    Actually creates the CompiledMethod object and installs it in the
  465.  *    current method dictionary with the selector derived from the method
  466.  *    expression.
  467.  *
  468.  * Inputs
  469.  *
  470.  *    method: A syntax tree node for a method definition.
  471.  *
  472.  */
  473. void compileMethod(method)
  474. TreeNode method;
  475. {
  476.   TreeNode    statement;
  477.   OOP        selector;
  478.   ByteCodes    byteCodes;
  479.  
  480.   dupMessageReceiver = false;
  481.  
  482.   initCompiler();
  483.   declareArguments(method->vMethod.selectorExpr);
  484.   declareTemporaries(method->vMethod.temporaries);
  485.  
  486.   if (setjmp(badMethod) == 0) {
  487.     for (statement = method->vMethod.statements; statement;
  488.      statement = statement->vExpr.expression) {
  489.       compileStatement(statement->vExpr.receiver);
  490.       if (statement->vExpr.receiver->nodeType != returnExprType) {
  491.     if (statement->vExpr.expression == nil) {
  492.       /* compile a return of self */
  493.       compileByte(returnIndexed | receiverIndex);
  494.     } else {
  495.       /* ignore the result of the last statement if it's not used */
  496.       compileByte(popStackTop);
  497.     }
  498.       }
  499.     }
  500.  
  501.     if (method->vMethod.statements == nil) {
  502.       /* special case an empty statement body to return self */
  503.       /* ??? this could compile some kind of primitive failure message, 
  504.      I guess */
  505.       compileByte(returnIndexed | receiverIndex);
  506.     }
  507.  
  508.     if (hasExtendedSuper) {
  509.       addMethodClassVariable();
  510.     }
  511.  
  512.     selector = computeSelector(method->vMethod.selectorExpr);
  513.     byteCodes = getByteCodes();
  514.     byteCodes = optimizeByteCodes(byteCodes);
  515.  
  516.     installMethod(selector, method->vMethod.primitiveIndex,
  517.           getArgCount(), getTempCount(),
  518.           getMethodLiterals(), byteCodes);
  519.   } else {
  520.     hadError = true;
  521.   }
  522.  
  523.   undeclareTemporaries(method->vMethod.temporaries);
  524.   undeclareArguments(method->vMethod.selectorExpr);
  525.   freeTree(method);
  526. }
  527.  
  528. /*
  529.  *    static void compileStatement(stmt)
  530.  *
  531.  * Description
  532.  *
  533.  *    Compiles a statement expression, including return expressions.
  534.  *
  535.  * Inputs
  536.  *
  537.  *    stmt  : A stmt tree node.
  538.  *
  539.  */
  540. static void compileStatement(stmt)
  541. TreeNode stmt;
  542. {
  543.   int        index;
  544.  
  545.   switch (stmt->nodeType) {
  546.   case constExprType:
  547.   case blockNodeType:
  548.     index = -1;
  549.     break;
  550.  
  551.   default:
  552.     index = isSpecialVariable(stmt->vExpr.receiver);
  553.   }
  554.  
  555.   if (index < 0) {
  556.     if (stmt->nodeType == returnExprType) {
  557.       compileExpression(stmt->vExpr.receiver);
  558.       compileByte(returnMethodStackTop);
  559.     } else {
  560.       compileExpression(stmt);
  561.     }
  562.   } else {
  563.     if (stmt->nodeType == returnExprType) {
  564.       /* return one of {self, true, false, nil} */
  565.       compileByte(returnIndexed | index);
  566.     } else {
  567.       compileExpression(stmt);
  568.     }
  569.   }
  570. }
  571.  
  572. /*
  573.  *    static void compileExpression(expr)
  574.  *
  575.  * Description
  576.  *
  577.  *    Compile an arbitrary expression, including an assignment expression.
  578.  *
  579.  * Inputs
  580.  *
  581.  *    expr  : A syntax tree node for an expression, including assignments.
  582.  *
  583.  */
  584. static void compileExpression(expr)
  585. TreeNode expr;
  586. {
  587.   if (expr->nodeType == assignExprType) {
  588.     compileSimpleExpression(expr->vExpr.expression);
  589.     compileAssignments(expr->vExpr.receiver);
  590.   } else {
  591.     compileSimpleExpression(expr);
  592.   }
  593. }
  594.  
  595. /*
  596.  *    static void compileSimpleExpression(expr)
  597.  *
  598.  * Description
  599.  *
  600.  *    The basic expression compiler.  Can be called recursively.  Dispatches
  601.  *    based on the type of the expression to different routines that
  602.  *    specialize in compilations for that expression.
  603.  *
  604.  * Inputs
  605.  *
  606.  *    expr  : A syntax tree node for some kind of expression.
  607.  *
  608.  */
  609. static void compileSimpleExpression(expr)
  610. TreeNode expr;
  611. {
  612.   switch (expr->nodeType) {
  613.   case variableNodeType:
  614.     compileVariable(expr);
  615.     break;
  616.   case constExprType:
  617.     compileConstant(expr);
  618.     break;
  619.   case blockNodeType:
  620.     compileBlock(expr);
  621.     break;
  622.   case unaryExprType:
  623.     compileUnaryExpr(expr);
  624.     break;
  625.   case binaryExprType:
  626.     compileBinaryExpr(expr);
  627.     break;
  628.   case keywordExprType:
  629.     compileKeywordExpr(expr);
  630.     break;
  631.   case cascadedMessageNodeType:
  632.     compileCascadedMessage(expr);
  633.     break;
  634.   default:
  635.     compileExpression(expr);
  636.   }
  637. }
  638.  
  639. /*
  640.  *    static void compileVariable(varName)
  641.  *
  642.  * Description
  643.  *
  644.  *    Compile code to push the value of a variable onto the stack.  The
  645.  *    special variables, self, true, false, super, and thisContext, are
  646.  *    handled specially.  For other variables, different code is emitted
  647.  *    depending on where the variable lives, such as in a global variable or
  648.  *    in a method temporary.
  649.  *
  650.  * Inputs
  651.  *
  652.  *    varName: 
  653.  *        A syntax tree node that indicates a variable name.
  654.  *
  655.  */
  656. static void compileVariable(varName)
  657. TreeNode varName;
  658. {
  659.   SymbolEntry    variable;
  660.   int        index, location;
  661.  
  662.   index = isSpecialVariable(varName);
  663.   if (index >= 0) {
  664.     compileByte(pushSpecial | index);
  665.     return;
  666.   }
  667.  
  668.   if (internString(varName->vList.name) == thisContextSymbol) {
  669.     compileByte(pushActiveContext);
  670.     return;
  671.   }
  672.  
  673.   variable = findVariable(varName->vList.name);
  674.   if (variable == nil) {
  675.     errorf("Undefined variable %s referenced", varName->vList.name);
  676.     longjmp(badMethod, 1);
  677.   }
  678.   
  679.   if (variable->scope == temporaryScope || variable->scope == receiverScope) {
  680.     if (variable->varIndex <= 15) {
  681.       if (variable->scope == temporaryScope) {
  682.     compileByte(pushTemporaryVariable | variable->varIndex);
  683.       } else {
  684.     compileByte(pushReceiverVariable | variable->varIndex);
  685.       }
  686.     } else {
  687.       compileByte(pushIndexed);
  688.       location = (variable->scope == temporaryScope)
  689.     ? temporaryLocation : receiverLocation;
  690.       compileByte(location | variable->varIndex);
  691.     }
  692.   } else {
  693.     if (variable->varIndex <= 31) {
  694.       compileByte(pushLitVariable | variable->varIndex);
  695.     } else {
  696.       /* ??? check for variable index too large here? */
  697.       compileByte(pushIndexed);
  698.       compileByte(litVarLocation | variable->varIndex);
  699.     }
  700.   }
  701.   freeSymbolEntry(variable);
  702. }
  703.  
  704. /*
  705.  *    static void compileConstant(constExpr)
  706.  *
  707.  * Description
  708.  *
  709.  *    Compile an expression that pushes a constant expression onto the stack.
  710.  *    Special cases out the constants that the byte code interpreter knows
  711.  *    about, which are the integers in the range -1 to 2.  Tries to emit the
  712.  *    shortest possible byte sequence.
  713.  *
  714.  * Inputs
  715.  *
  716.  *    constExpr: 
  717.  *        A syntax tree node that represents a literal constant.
  718.  *
  719.  */
  720. static void compileConstant(constExpr)
  721. TreeNode constExpr;
  722. {
  723.   int        index;
  724.  
  725.   index = addConstant(constExpr);
  726.   if (index < 0) {
  727.     compileByte(pushSpecial | (index + 3 + 5));
  728.   } else if (index <= 31) {
  729.     compileByte(pushLitConstant | index);
  730.   } else {
  731.     compileByte(pushIndexed);
  732.     compileByte(litConstLocation | index);
  733.   }
  734. }
  735.  
  736. /*
  737.  *    static void compileBlock(blockExpr)
  738.  *
  739.  * Description
  740.  *
  741.  *    Compile the expressions for a block.  Also, emits code to create the
  742.  *    block, and then to skip around it.  The block will have its initial
  743.  *    byte pointer pointing to two bytes past the long jump instruction, so
  744.  *    that when the block is invoked it will start off at the first byte of
  745.  *    the block.
  746.  *    
  747.  *
  748.  * Inputs
  749.  *
  750.  *    blockExpr: 
  751.  *        A syntax tree node for a block expression.
  752.  *
  753.  */
  754. static void compileBlock(blockExpr)
  755. TreeNode blockExpr;
  756. {
  757.   ByteCodes    currentByteCodes, blockByteCodes;
  758.  
  759.   currentByteCodes = saveByteCodeArray(); /* ??? don't like this name */
  760.  
  761.   declareBlockArguments(blockExpr->vMethod.temporaries);
  762.   compileBlockArguments(blockExpr->vMethod.temporaries);
  763.   compileStatements(blockExpr->vMethod.statements, true);
  764.   undeclareBlockArguments(blockExpr->vMethod.temporaries);
  765.  
  766.   blockByteCodes = getByteCodes();
  767.   restoreByteCodeArray(currentByteCodes);
  768.  
  769.   /* emit standard byte sequence to invoke a block:
  770.    *   push current context
  771.    *   push number of block args
  772.    *   blockCopy: send
  773.    *   long jump around block bytecodes
  774.    *   <block byte codes>...
  775.    */
  776.   compileByte(pushActiveContext);
  777.   compilePushIntConstant(listLength(blockExpr->vMethod.temporaries));
  778.   compileByte(blockCopyColonSpecial);
  779.   compileByte(jumpLong | (byteCodeLength(blockByteCodes)/256)+4);
  780.   compileByte(byteCodeLength(blockByteCodes) & 255);
  781.   compileAndFreeByteCodes(blockByteCodes);
  782.  
  783. }
  784.  
  785. /*
  786.  *    static void compileBlockArguments(args)
  787.  *
  788.  * Description
  789.  *
  790.  *    On entry to a block, its arguments (if any) are on the stack.  Since
  791.  *    there is no way to refer to them via byte codes on the stack, the
  792.  *    correct procedure is to pop them into temporary locations in the method
  793.  *    itself.  Since we're popping from a stack, we need to pop the arguments
  794.  *    in reverse order from the order that they are declared.  Args is a list
  795.  *    of TreeNodes in declaration order, so we recurse to get the last one,
  796.  *    pop it, get the penultimate, pop it, etc.  This routine works even if
  797.  *    args is nil, in which case the block had no arguments.
  798.  *
  799.  * Inputs
  800.  *
  801.  *    args  : a TreeNode of type ListNode that is a list of argument names to
  802.  *        the block being compiled.
  803.  *
  804.  */
  805. static void compileBlockArguments(args)
  806. TreeNode args;
  807. {
  808.   SymbolEntry    variable;
  809.  
  810.   if (args == nil) {
  811.     return;
  812.   }
  813.  
  814.   compileBlockArguments(args->vList.next);
  815.   variable = findVariable(args->vList.name);
  816.   if (variable->varIndex <= 7) {
  817.     compileByte(popTemporaryVariable | variable->varIndex);
  818.   } else {
  819.     compileByte(popStoreIndexed);
  820.     compileByte(temporaryLocation | variable->varIndex);
  821.   }
  822.   freeSymbolEntry(variable);
  823. }
  824.  
  825. /*
  826.  *    static void compileStatements(statementList, isBlock)
  827.  *
  828.  * Description
  829.  *
  830.  *    Compiles all of the statements in statement list.  Makes the final
  831.  *    instruction of the block be a return top of stack, if the final
  832.  *    statement isn't a return (^).
  833.  *
  834.  * Inputs
  835.  *
  836.  *    statementList: 
  837.  *        A TreeNode of type ExprNode that is the list of statements in
  838.  *        the block.  If it is nil, the block's return value is nil.
  839.  *    isBlock:A boolean.  If true, these statements are from a block
  840.  *        context.  If false, they are just an ordinary statement list.
  841.  */
  842. static void compileStatements(statementList, isBlock)
  843. TreeNode statementList;
  844. Boolean    isBlock;
  845. {
  846.   TreeNode    stmt;
  847.  
  848.   if (statementList == nil) {
  849.     if (isBlock) {
  850.       compileByte(returnIndexed | nilIndex);
  851.     } else {
  852.       compileByte(pushSpecial | nilIndex);
  853.     }
  854.     return;
  855.   }
  856.   
  857.   for(stmt = statementList ; stmt; stmt = stmt->vExpr.expression) {
  858.     compileStatement(stmt->vExpr.receiver);
  859.     if (stmt->vExpr.expression == nil) {
  860.       if (stmt->vExpr.receiver->nodeType != returnExprType) {
  861.     /* if last statement isn't a return, then return the value on the
  862.        stack as the result.  For non-block contexts, returning the top
  863.        of the stack is the default, so it's ok.*/
  864.     if (isBlock) {
  865.       compileByte(returnBlockStackTop);
  866.     }
  867.       }
  868.     } else {
  869.       /* throw away the value on the top of the stack...we don't need it
  870.      for all but the last one. */
  871.       compileByte(popStackTop);
  872.     }
  873.   }
  874. }
  875.  
  876.  
  877. /*
  878.  *    static void compileUnaryExpr(expr)
  879.  *
  880.  * Description
  881.  *
  882.  *    Compile code to evaluate a unary expression.  Special cases sends to
  883.  *    "super" and duplicates the receiver's value if this is part of a
  884.  *    cascaded message send.
  885.  *
  886.  * Inputs
  887.  *
  888.  *    expr  : A syntax tree node for a unary expression.
  889.  *
  890.  */
  891. static void compileUnaryExpr(expr)
  892. TreeNode expr;
  893. {
  894.   OOP        selector;
  895.   int        selectorIndex;
  896.   Boolean    savedDupFlag;
  897.  
  898.   savedDupFlag = dupMessageReceiver;
  899.   dupMessageReceiver = false;
  900.  
  901.   selector = expr->vExpr.selector;
  902.   selectorIndex = addSelector(selector);
  903.  
  904.   if (expr->vExpr.receiver != nil) {
  905.     compileExpression(expr->vExpr.receiver);
  906.     if (savedDupFlag) {
  907.       compileByte(dupStackTop);
  908.     }
  909.     if (isSuper(expr->vExpr.receiver)) {
  910.       if (selectorIndex < 0) {
  911.     selectorIndex = addForcedSelector(selector);
  912.       }
  913.       hasExtendedSuper = true;
  914.       if (selectorIndex <= 31) {
  915.     compileByte(sendSuper1ExtByte);
  916.     compileByte(selectorIndex);
  917.       } else {
  918.     compileByte(sendSuper2ExtByte);
  919.     compileByte(0);
  920.     compileByte(selectorIndex);
  921.       }
  922.       return;
  923.     }
  924.   }
  925.   
  926.   if (isNil(selector)) {
  927.     errorf("Nil selector in unary expression");
  928.     longjmp(badMethod, 1);
  929.   }
  930.  
  931.   if (selectorIndex < 0) {
  932.     compileByte(-selectorIndex);
  933.   } else {
  934.     compileSend(selectorIndex, 0);
  935.   }
  936. }
  937.  
  938. /*
  939.  *    static void compileBinaryExpr(expr)
  940.  *
  941.  * Description
  942.  *
  943.  *    Compiles code for a binary message.  Special cases sends to super, as
  944.  *    they get different byte codes.  Also, checks to see if it's the first
  945.  *    part of a cascaded message send and if so emits code to duplicate the
  946.  *    stack top after the evaluation of the receiver for use by the
  947.  *    subsequent cascaded expressions.
  948.  *
  949.  * Inputs
  950.  *
  951.  *    expr  : A syntax tree node for a binary expression.
  952.  *
  953.  */
  954. static void compileBinaryExpr(expr)
  955. TreeNode expr;
  956. {
  957.   OOP        selector;
  958.   int        selectorIndex;
  959.   Boolean    savedDupFlag;
  960.  
  961.   savedDupFlag = dupMessageReceiver;
  962.   dupMessageReceiver = false;
  963.  
  964.   selector = expr->vExpr.selector;
  965.   selectorIndex = addSelector(selector);
  966.  
  967.   if (expr->vExpr.receiver) {
  968.     compileExpression(expr->vExpr.receiver);
  969.     if (savedDupFlag) {
  970.       compileByte(dupStackTop);
  971.     }
  972.   }
  973.   if (expr->vExpr.expression) {
  974.     compileExpression(expr->vExpr.expression);
  975.   }
  976.  
  977.   if (expr->vExpr.receiver) {
  978.     if (isSuper(expr->vExpr.receiver)) {
  979.       if (selectorIndex < 0) {
  980.     selectorIndex = addForcedSelector(selector);
  981.       }
  982.       hasExtendedSuper = true;
  983.       if (selectorIndex <= 31) {
  984.     compileByte(sendSuper1ExtByte);
  985.     compileByte((1 << 5) | selectorIndex);
  986.       } else {
  987.     compileByte(sendSuper2ExtByte);
  988.     compileByte(1);
  989.     compileByte(selectorIndex);
  990.       }
  991.     }
  992.   }
  993.  
  994.   if (isNil(selector)) {
  995.     errorf("nil selector in binary expression");
  996.     longjmp(badMethod, 1);
  997.   }
  998.  
  999.   if (selectorIndex < 0) {
  1000.     compileByte(-selectorIndex);
  1001.   } else {
  1002.     compileSend(selectorIndex, 1);
  1003.   }
  1004. }
  1005.  
  1006. /*
  1007.  *    static void compileKeywordExpr(expr)
  1008.  *
  1009.  * Description
  1010.  *
  1011.  *    Compile an keyword message send.  Special cases out while loops, the 4
  1012.  *    kinds of if tests, and the conditional "and" and conditional "or"
  1013.  *    messages.  If the expression isn't one of these, the expression is
  1014.  *    evaluated normally.  Has special hacks to support the duplication of
  1015.  *    the receiver's value in the case of the first part of a cascaded
  1016.  *    message send.
  1017.  *
  1018.  * Inputs
  1019.  *
  1020.  *    expr  : A syntax tree node that represents a keyword message send
  1021.  *        expression.
  1022.  *
  1023.  */
  1024. static void compileKeywordExpr(expr)
  1025. TreeNode expr;
  1026. {
  1027.   OOP        selector;
  1028.   int        selectorIndex, numArgs;
  1029.   Boolean    savedDupFlag;
  1030.  
  1031.   savedDupFlag = dupMessageReceiver;
  1032.   dupMessageReceiver = false;
  1033.  
  1034.   selector = computeSelector(expr);
  1035.  
  1036.   /* check for optimized cases of messages to booleans and handle them
  1037.      specially */
  1038.   if (selector == whileTrueColonSymbol || selector == whileFalseColonSymbol) {
  1039.     if (compileWhileLoop(selector, expr)) {
  1040.       return;
  1041.     }
  1042.   }
  1043.  
  1044.   if (expr->vExpr.receiver) {
  1045.     compileExpression(expr->vExpr.receiver);
  1046.     if (savedDupFlag) {
  1047.       compileByte(dupStackTop);
  1048.     }
  1049.   }
  1050.  
  1051.   if (selector == ifTrueColonSymbol || selector == ifFalseColonSymbol) {
  1052.     if (compileIfStatement(selector, expr->vExpr.expression)) {
  1053.       return;
  1054.     }
  1055.   } else if (selector == ifTrueColonIfFalseColonSymbol
  1056.          || selector == ifFalseColonIfTrueColonSymbol) {
  1057.     if (compileIfTrueFalseStatement(selector, expr->vExpr.expression)) {
  1058.       return;
  1059.     }
  1060.   } else if (selector == andColonSymbol || selector == orColonSymbol) {
  1061.     if (compileAndOrStatement(selector, expr->vExpr.expression)) {
  1062.       return;
  1063.     }
  1064.   }
  1065.  
  1066.   selectorIndex = addSelector(selector);
  1067.   numArgs = listLength(expr->vExpr.expression);
  1068.  
  1069.   compileKeywordList(expr->vExpr.expression);
  1070.  
  1071.   if (expr->vExpr.receiver) {
  1072.     if (isSuper(expr->vExpr.receiver)) {
  1073.       if (selectorIndex < 0) {
  1074.     selectorIndex = addForcedSelector(selector);
  1075.       }
  1076.       hasExtendedSuper = true;
  1077.       if (selectorIndex <= 31 && numArgs <= 7) {
  1078.     compileByte(sendSuper1ExtByte);
  1079.     compileByte((numArgs << 5) | selectorIndex);
  1080.       } else {
  1081.     compileByte(sendSuper2ExtByte);
  1082.     compileByte(numArgs);
  1083.     compileByte(selectorIndex);
  1084.       }
  1085.       return;
  1086.     }
  1087.   }
  1088.  
  1089.   if (selectorIndex < 0) {
  1090.     compileByte(-selectorIndex);
  1091.   } else {
  1092.     compileSend(selectorIndex, numArgs);
  1093.   }
  1094. }
  1095.  
  1096. /*
  1097.  *    static void compileKeywordList(list)
  1098.  *
  1099.  * Description
  1100.  *
  1101.  *    Emit code to evaluate each argument to a keyword message send.
  1102.  *
  1103.  * Inputs
  1104.  *
  1105.  *    list  : A list of expressions that represents the arguments to be
  1106.  *        evaluated.  A syntax tree node.
  1107.  *
  1108.  */
  1109. static void compileKeywordList(list)
  1110. TreeNode list;
  1111. {
  1112.   for (; list; list = list->vList.next) {
  1113.     compileExpression(list->vList.value);
  1114.   }
  1115. }
  1116.  
  1117. /*
  1118.  *    static Boolean compileWhileLoop(selector, expr)
  1119.  *
  1120.  * Description
  1121.  *
  1122.  *    Special case compilation of a #whileTrue: or #whileFalse: loop.
  1123.  *
  1124.  * Inputs
  1125.  *
  1126.  *    selector: 
  1127.  *        Symbol, one of #whileTrue: or #whileFalse:.
  1128.  *    expr  : An expression that represents the entire while loop.
  1129.  *
  1130.  * Outputs
  1131.  *
  1132.  *    True if byte codes were emitted, false if not.  If either the receiver
  1133.  *    and the argument to the while message are not block expressions, this
  1134.  *    routine cannot do it's job, and so returns false to indicate as much.
  1135.  */
  1136. static Boolean compileWhileLoop(selector, expr)
  1137. OOP    selector;
  1138. TreeNode expr;
  1139. {
  1140.   int        whileLoopLen, startLoopLen;
  1141.   ByteCodes    receiverExprCodes, whileExprCodes;
  1142.  
  1143.   if (expr->vExpr.receiver->nodeType != blockNodeType
  1144.       || expr->vExpr.expression->vList.value->nodeType != blockNodeType) {
  1145.     return (false);
  1146.   }
  1147.  
  1148.   startLoopLen = currentByteCodeLength();
  1149.  
  1150.   receiverExprCodes = compileSubExpression(expr->vExpr.receiver);
  1151.   whileExprCodes = compileSubExpression(expr->vExpr.expression->vList.value);
  1152.   compileAndFreeByteCodes(receiverExprCodes);
  1153.  
  1154.   /* skip around the while expr and the pop stack top and the 2 byte goto
  1155.      that follows if the condition doesn't match the while test. */
  1156.   compileJump(byteCodeLength(whileExprCodes)+3,
  1157.           (selector == whileTrueColonSymbol) ? falseJump : trueJump);
  1158.  
  1159.   compileAndFreeByteCodes(whileExprCodes);
  1160.   compileByte(popStackTop);    /* we don't care about while expr's value */
  1161.  
  1162.   /* +2 since we're using a 2 byte jump instruction here, so we have to
  1163.      skip back over it in addition to the other instructions */
  1164.   whileLoopLen = currentByteCodeLength() - startLoopLen +2;
  1165.   /* this is a backwards branch, but you can't tell it */
  1166.   compileByte(jumpLong | (4 - ((whileLoopLen+255)/256)));
  1167.   compileByte((-whileLoopLen) & 255);
  1168.   
  1169.   compileByte(pushSpecial | nilIndex);
  1170.   return (true);
  1171. }
  1172.  
  1173. /*
  1174.  *    static Boolean compileIfTrueFalseStatement(selector, expr)
  1175.  *
  1176.  * Description
  1177.  *
  1178.  *    Special case compile of the code for #ifTrue:false: and #ifFalse:true:
  1179.  *    messages.
  1180.  *
  1181.  * Inputs
  1182.  *
  1183.  *    selector: 
  1184.  *        Symbol, one of #ifTrue:false: or #ifFalse:true:
  1185.  *    expr  : An tree node that represents the expressions for the first and
  1186.  *        second arguments to the message.  If either is not a block type
  1187.  *        expression, no byte codes are emitted, and this routine
  1188.  *        returns false.
  1189.  *
  1190.  * Outputs
  1191.  *
  1192.  *    True if the byte codes to perform the test were successfully emitted,
  1193.  *    false if not.
  1194.  */
  1195. static Boolean compileIfTrueFalseStatement(selector, expr)
  1196. OOP    selector;
  1197. TreeNode expr;
  1198. {
  1199.   ByteCodes    trueByteCodes, falseByteCodes;
  1200.  
  1201.   if (expr->vList.value->nodeType != blockNodeType
  1202.       || expr->vList.next->vList.value->nodeType != blockNodeType) {
  1203.     return (false);
  1204.   }
  1205.  
  1206.   if (selector == ifTrueColonIfFalseColonSymbol) {
  1207.     falseByteCodes = compileSubExpression(expr->vList.next->vList.value);
  1208.     trueByteCodes =
  1209.       compileSubExpressionWithGoto(expr->vList.value,
  1210.                    byteCodeLength(falseByteCodes));
  1211.   } else {
  1212.     falseByteCodes = compileSubExpression(expr->vList.value);
  1213.     trueByteCodes =
  1214.       compileSubExpressionWithGoto(expr->vList.next->vList.value,
  1215.                    byteCodeLength(falseByteCodes));
  1216.   }
  1217.  
  1218.   compileJump(byteCodeLength(trueByteCodes), falseJump);
  1219.   compileAndFreeByteCodes(trueByteCodes);
  1220.   compileAndFreeByteCodes(falseByteCodes);
  1221.   return (true);
  1222. }
  1223.  
  1224. /*
  1225.  *    static Boolean compileIfStatement(selector, expr)
  1226.  *
  1227.  * Description
  1228.  *
  1229.  *    Special case compile of code for an #ifTrue: or #ifFalse: message.  The
  1230.  *    default value of an "if" type message is nil.
  1231.  *
  1232.  * Inputs
  1233.  *
  1234.  *    selector: 
  1235.  *        Symbol, one of #ifTrue: or #ifFalse:
  1236.  *    expr  : An expression to be evaluated if the given condition holds.
  1237.  *
  1238.  * Outputs
  1239.  *
  1240.  *    True if byte codes were emitted, false if not (as is the case if the
  1241.  *    expression following the selector is not a block).
  1242.  */
  1243. static Boolean compileIfStatement(selector, expr)
  1244. OOP    selector;
  1245. TreeNode expr;
  1246. {
  1247.   ByteCodes    thenByteCodes, defaultByteCodes;
  1248.   Boolean    hasElse;
  1249.  
  1250.   if (expr->vList.value->nodeType != blockNodeType) {
  1251.     return (false);
  1252.   }
  1253.  
  1254.   thenByteCodes = compileSubExpression(expr->vList.value);
  1255.   defaultByteCodes = compileDefaultValue(nilIndex,
  1256.                      byteCodeLength(thenByteCodes));
  1257.   compileJump(byteCodeLength(defaultByteCodes),
  1258.           (selector == ifTrueColonSymbol) ? trueJump : falseJump);
  1259.   compileAndFreeByteCodes(defaultByteCodes);
  1260.   compileAndFreeByteCodes(thenByteCodes);
  1261.   return (true);
  1262. }
  1263.  
  1264.  
  1265.  
  1266. /*
  1267.  *    static Boolean compileAndOrStatement(selector, expr)
  1268.  *
  1269.  * Description
  1270.  *
  1271.  *    Special casing for and: an or: messages.  Emits code that jumps on the
  1272.  *    condition (true for and:, false for or:) to the actual expression for
  1273.  *    the block that's the argument to the message.  Then emits code that
  1274.  *    pushes the default value onto the stack, which will be only executed in
  1275.  *    the failure cases.  Then emits the code for the evaluation of the block
  1276.  *    that's the argument to the message.
  1277.  *
  1278.  * Inputs
  1279.  *
  1280.  *    selector: 
  1281.  *        A Symbol, either #and: or #or:.
  1282.  *    expr  : A syntax tree piece that represents the expressions contained
  1283.  *        in the block that's passed as an argument of the message.
  1284.  *
  1285.  * Outputs
  1286.  *
  1287.  *    Returns true if the code was successfully emitted, and false if the
  1288.  *    code was not (such as a non-block following the selector).
  1289.  */
  1290. static Boolean compileAndOrStatement(selector, expr)
  1291. OOP    selector;
  1292. TreeNode expr;
  1293. {
  1294.   ByteCodes    blockByteCodes, defaultByteCodes;
  1295.   int        blockLen;
  1296.   
  1297.   /* I elected for simplicty sake to just emit the same kind of code always,
  1298.      and not try to save a byte by using the jump false. */
  1299.  
  1300.   if (expr->vList.value->nodeType != blockNodeType) {
  1301.     return (false);
  1302.   }
  1303.  
  1304.   blockByteCodes = compileSubExpression(expr->vList.value);
  1305.   blockLen = byteCodeLength(blockByteCodes);
  1306.   defaultByteCodes = compileDefaultValue((selector == andColonSymbol)
  1307.                      ? falseIndex : trueIndex, blockLen);
  1308.   compileJump(byteCodeLength(defaultByteCodes),
  1309.           (selector == andColonSymbol) ? trueJump : falseJump);
  1310.   compileAndFreeByteCodes(defaultByteCodes);
  1311.   compileAndFreeByteCodes(blockByteCodes);
  1312.   return (true);
  1313. }
  1314.  
  1315. /*
  1316.  *    static ByteCodes compileDefaultValue(litIndex, realExprLen)
  1317.  *
  1318.  * Description
  1319.  *
  1320.  *    Compiles and returns a byte code sequence that represents the default
  1321.  *    value of a conditional expression, such as IfTrue: when the receiver is
  1322.  *    false.  The sequence causes the default value to be pushed on the
  1323.  *    stack, and then the byte codes for the non-default value to be jumped
  1324.  *    around.
  1325.  *
  1326.  * Inputs
  1327.  *
  1328.  *    litIndex: 
  1329.  *        The index for the value to push, typcially one of true, false,
  1330.  *        or nil.  Used as part of a pushSpecial byte code.
  1331.  *    realExprLen: 
  1332.  *        A C int that represents the length of the byte codes that are
  1333.  *        evaluated in the non-default case.
  1334.  *
  1335.  * Outputs
  1336.  *
  1337.  *    A sequence of byte codes pushes the default value and skips around the
  1338.  *    computation of the real value.
  1339.  */
  1340. static ByteCodes compileDefaultValue(litIndex, realExprLen)
  1341. int    litIndex, realExprLen;
  1342. {
  1343.   ByteCodes    currentByteCodes, defaultByteCodes;
  1344.  
  1345.   currentByteCodes = saveByteCodeArray(); /* ??? don't like this name */
  1346.  
  1347.   compileByte(pushSpecial | litIndex);
  1348.   compileJump(realExprLen, unconditionalJump);
  1349.  
  1350.   defaultByteCodes = getByteCodes();
  1351.   restoreByteCodeArray(currentByteCodes);
  1352.  
  1353.   return (defaultByteCodes);
  1354. }
  1355.  
  1356. /*
  1357.  *    static ByteCodes compileSubExpression(expr)
  1358.  *
  1359.  * Description
  1360.  *
  1361.  *    Compile a "block" in a separate context and return the resulting
  1362.  *    bytecodes.  The block will not have argument declarations as it's only
  1363.  *    the code for things like ifTrue:, and:, whileTrue:, etc.  It is
  1364.  *    compiled as a list of statements such that the last statement leaves
  1365.  *    the value that is produced on the stack, as the value of the "block".
  1366.  *
  1367.  * Inputs
  1368.  *
  1369.  *    expr  : A "block" TreeNode that has no arguments. 
  1370.  *
  1371.  * Outputs
  1372.  *
  1373.  *    A ByteCodes vector of byte codes that represent the execution of the
  1374.  *    statements in the "block".
  1375.  */
  1376. static ByteCodes compileSubExpression(expr)
  1377. TreeNode expr;
  1378. {
  1379.   return (compileSubExpressionWithGoto(expr, 0));
  1380. }
  1381.  
  1382.  
  1383. /*
  1384.  *    static ByteCodes compileSubExpressionWithGoto(expr, branchLen)
  1385.  *
  1386.  * Description
  1387.  *
  1388.  *    Like compileSubExpression, except that this sub expression always ends
  1389.  *    with an unconditional branch past "branchLen" bytecodes.
  1390.  *
  1391.  * Inputs
  1392.  *
  1393.  *    expr  : a TreeNode that looks like a "block".
  1394.  *    branchLen: 
  1395.  *        number of bytes to skip over, possibly zero (in which case no
  1396.  *        goto is generated).
  1397.  *
  1398.  * Outputs
  1399.  *
  1400.  *    ByteCodes that represent the execution of the statements in "expr",
  1401.  *    with a goto after them (if "branchLen" is nonzero).
  1402.  */
  1403. static ByteCodes compileSubExpressionWithGoto(expr, branchLen)
  1404. TreeNode expr;
  1405. int    branchLen;
  1406. {
  1407.   ByteCodes    currentByteCodes, subExprByteCodes;
  1408.  
  1409.   currentByteCodes = saveByteCodeArray(); /* ??? don't like this name */
  1410.  
  1411.   compileStatements(expr->vMethod.statements, false);
  1412.   if (branchLen) {
  1413.     compileJump(branchLen, unconditionalJump);
  1414.   }
  1415.  
  1416.   subExprByteCodes = getByteCodes();
  1417.   restoreByteCodeArray(currentByteCodes);
  1418.  
  1419.   return (subExprByteCodes);
  1420. }
  1421.  
  1422. /*
  1423.  *    static void compileJump(len, jumpType)
  1424.  *
  1425.  * Description
  1426.  *
  1427.  *    Compiles a jump instruction, using the smallest possible number of byte
  1428.  *    codes.  Special cases for the unconditional jump and the short false
  1429.  *    jump that the byte code interpreter handles.
  1430.  *
  1431.  * Inputs
  1432.  *
  1433.  *    len   : Number of byte codes to jump forward (only forward jumps are
  1434.  *        handled.  A C int > 0.
  1435.  *    jumpType: 
  1436.  *        An enumerated value that indicates whether the jump is
  1437.  *        unconditional, or a true or false jump.
  1438.  *
  1439.  */
  1440. static void compileJump(len, jumpType)
  1441. int    len;
  1442. JumpType jumpType;
  1443. {
  1444.   if (len <= 0) {
  1445.     errorf("Illegal length jump %d\n", len);
  1446.     longjmp(badMethod, 1);
  1447.   }
  1448.  
  1449.   switch (jumpType) {
  1450.   case unconditionalJump:
  1451.     if (len <= 8) {
  1452.       compileByte(jumpShort | (len - 1));
  1453.     } else {
  1454.       compileByte(jumpLong | (4 + len/256));
  1455.       compileByte(len & 255);
  1456.     }
  1457.     break;
  1458.  
  1459.   case falseJump:
  1460.     if (len <= 8) {
  1461.       compileByte(popJumpFalseShort | (len - 1));
  1462.     } else {
  1463.       compileByte(popJumpFalse | (len/256));
  1464.       compileByte(len & 255);
  1465.     }
  1466.     break;
  1467.  
  1468.   case trueJump:
  1469.     compileByte(popJumpTrue | (len/256));
  1470.     compileByte(len & 255);
  1471.     break;
  1472.   }
  1473. }
  1474.  
  1475. /*
  1476.  *    compilePushIntConstant(intConst)
  1477.  *
  1478.  * Description
  1479.  *
  1480.  *    Compiles an instruction to push an Integer constant on the stack.
  1481.  *    Special cases out the literals -1..2, and tries to emit the shortest
  1482.  *    possible byte sequence to get the job done.
  1483.  *
  1484.  * Inputs
  1485.  *
  1486.  *    intConst: 
  1487.  *        The constant to be pushed; a C int.
  1488.  *
  1489.  */
  1490. compilePushIntConstant(intConst)
  1491. int    intConst;
  1492. {
  1493.   TreeNode    constExpr;
  1494.   int        constIndex;
  1495.  
  1496.   if (intConst >= -1 && intConst <= 2) {
  1497.     compileByte(pushSpecial | intConst + 5);
  1498.     return;
  1499.   }
  1500.  
  1501.   /* a hack to make use of the functionality provided by addConstant */
  1502.   constExpr = makeIntConstant((long)intConst);
  1503.   constIndex = addConstant(constExpr);
  1504.   freeTree(constExpr);
  1505.   
  1506.   if (constIndex <= 31) {
  1507.     compileByte(pushLitConstant | constIndex);
  1508.   } else {
  1509.     compileByte(pushIndexed | litConstLocation);
  1510.     compileByte(constIndex);
  1511.   }
  1512. }
  1513.  
  1514.  
  1515. /*
  1516.  *    static void compileSend(selectorIndex, numArgs)
  1517.  *
  1518.  * Description
  1519.  *
  1520.  *    Compile a message send byte code.  Tries to use the minimal length byte
  1521.  *    code sequence; does not know about the special messages that the
  1522.  *    interpreter has "wired in"; those should be handled specially and this
  1523.  *    routine should not be called with them (it's ok if it is, just not
  1524.  *    quite as efficient).
  1525.  *
  1526.  * Inputs
  1527.  *
  1528.  *    selectorIndex: 
  1529.  *        The index in the literal vector of the selector for the send
  1530.  *    numArgs: 
  1531.  *        The number of arguments that the selector takes. A C integer.
  1532.  *
  1533.  */
  1534. static void compileSend(selectorIndex, numArgs)
  1535. int    selectorIndex, numArgs;
  1536. {
  1537.   if (numArgs <= 2 && selectorIndex <= 15) {
  1538.     switch (numArgs) {
  1539.     case 0:
  1540.       compileByte(sendSelectorNoArg | selectorIndex);
  1541.       break;
  1542.     case 1:
  1543.       compileByte(sendSelector1Arg | selectorIndex);
  1544.       break;
  1545.     case 2:
  1546.       compileByte(sendSelector2Arg | selectorIndex);
  1547.       break;
  1548.     }
  1549.   } else if (selectorIndex <= 31 && numArgs <= 7) {
  1550.     compileByte(sendSelector1ExtByte);
  1551.     compileByte((numArgs << 5) | selectorIndex);
  1552.   } else {
  1553.     compileByte(sendSelector2ExtByte);
  1554.     compileByte(numArgs);
  1555.     compileByte(selectorIndex);
  1556.   }
  1557. }
  1558.  
  1559. /*
  1560.  *    static void compileCascadedMessage(cascadedExpr)
  1561.  *
  1562.  * Description
  1563.  *
  1564.  *    Compiles the code for a cascaded message send.  Due to the fact that
  1565.  *    cascaded sends go to the receiver of the last message before the first
  1566.  *    cascade "operator" (the ";"), the system to perform cascaded message
  1567.  *    sends is a bit kludgy.  We basically turn on a flag to the compiler
  1568.  *    that indicates that the value of the receiver of the last message
  1569.  *    before the cascaded sends is to be duplicated; and then compile code
  1570.  *    for each cascaded expression, throwing away the result, and duplicating
  1571.  *    the original receiver so that it can be used by the current message
  1572.  *    send, and following ones.
  1573.  *
  1574.  * Inputs
  1575.  *
  1576.  *    cascadedExpr: 
  1577.  *        A tree node that represents a cascaded expression.  Both the
  1578.  *        initial receiver and all the subsequent cascaded sends can be
  1579.  *        derived from this node.
  1580.  *
  1581.  */
  1582. static void compileCascadedMessage(cascadedExpr)
  1583. TreeNode cascadedExpr;
  1584. {
  1585.   TreeNode message;
  1586.  
  1587.   dupMessageReceiver = true;
  1588.   compileExpression(cascadedExpr->vExpr.receiver);
  1589.  
  1590.   for(message = cascadedExpr->vExpr.expression; message;
  1591.       message = message->vList.next) {
  1592.     compileByte(popStackTop);
  1593.     if (message->vList.next) {
  1594.       compileByte(dupStackTop);
  1595.     }
  1596.     compileExpression(message->vList.value);
  1597.     /* !!! remember that unary, binary and keywordexpr should ignore the
  1598.        receiver field if it is nil; that is the case for these functions
  1599.        and things work out fine if that's the case. */
  1600.   }
  1601. }
  1602.  
  1603.  
  1604. /*
  1605.  *    static void compileAssignments(varList)
  1606.  *
  1607.  * Description
  1608.  *
  1609.  *    Compiles all the assignments in "varList", which is a TreeNode of type
  1610.  *    listNode.  The generated code assumes that the value on the top of the
  1611.  *    stack is what's to be used for the assignment.  Since this routine has
  1612.  *    no notion of now the value on top of the stack will be used by the
  1613.  *    calling environment, it makes sure that when the assignments are
  1614.  *    through, that the value on top of the stack after the assignment is the
  1615.  *    same as the value on top of the stack before the assignment.  The
  1616.  *    optimizer should fix this in the unnecessary cases. 
  1617.  *
  1618.  * Inputs
  1619.  *
  1620.  *    varList: 
  1621.  *            TreeNode of type listNode that contains the names of the
  1622.  *        variables to be assigned into.
  1623.  *
  1624.  */
  1625. static void compileAssignments(varList)
  1626. TreeNode varList;
  1627. {
  1628.   SymbolEntry    variable;
  1629.   int        locationIndex;
  1630.  
  1631.   for (; varList; varList = varList->vList.next) {
  1632.     variable = findVariable(varList->vList.name);
  1633.     if (variable == nil) {
  1634.       errorf("assignment to undeclared variable %s", varList->vList.name);
  1635.       longjmp(badMethod, 1);
  1636.     }
  1637.     /* Here we have several kinds of things to store: receiver variable,
  1638.        temporary variable, "literal" variable (reference by association). */
  1639.        
  1640.     if ((variable->scope == temporaryScope
  1641.     || variable->scope == receiverScope) && variable->varIndex <= 7) {
  1642.       compileByte(dupStackTop);
  1643.       compileByte(variable->scope == temporaryScope ?
  1644.           popTemporaryVariable | variable->varIndex :
  1645.           popReceiverVariable | variable->varIndex);
  1646.     } else {
  1647.       locationIndex = computeLocationIndex(variable);
  1648.       compileByte(storeIndexed);
  1649.       compileByte(locationIndex | variable->varIndex);
  1650.     }
  1651.     freeSymbolEntry(variable);
  1652.   }
  1653. }
  1654.  
  1655. /*
  1656.  *    static int computeLocationIndex(variable)
  1657.  *
  1658.  * Description
  1659.  *
  1660.  *    Given an internal representation of a variable, this routine returns
  1661.  *    an indicator of how to access the variable.  Depending on the source of
  1662.  *    the variable, this access location (which is actually to be compiled in
  1663.  *    as part of generated byte codes) can be an instance variable in the
  1664.  *    receiver, a temporary variable in the method context (includes
  1665.  *    arguments to the method) or a global or pool variable, which are
  1666.  *    referenced by a name/value Association.
  1667.  *
  1668.  * Inputs
  1669.  *
  1670.  *    variable: 
  1671.  *        Internal compiler variable.
  1672.  *
  1673.  * Outputs
  1674.  *
  1675.  *    Indication of how to access the variable.  A portion of a byte code
  1676.  *    that represents the various types of storage locations.
  1677.  */
  1678. static int computeLocationIndex(variable)
  1679. SymbolEntry variable;
  1680. {
  1681.   switch (variable->scope) {
  1682.   case receiverScope:
  1683.     return (receiverLocation);
  1684.   case temporaryScope:
  1685.     return (temporaryLocation);
  1686.   case globalScope: case poolScope:
  1687.     return (litVarLocation);
  1688.   }
  1689. }
  1690.  
  1691. /*
  1692.  *    static int isSpecialVariable(expr)
  1693.  *
  1694.  * Description
  1695.  *
  1696.  *    Examines the expression "expr" to see if it is a variable in the set
  1697.  *    "self", "false", "true", "nil".  Returns the "index" (number in 0..3)
  1698.  *    if true, -1 if false.  For this use, "super" is defined to be the
  1699.  *    equivalent of self.
  1700.  *
  1701.  * Inputs
  1702.  *
  1703.  *    expr  : TreeNode expression to be examined
  1704.  *
  1705.  * Outputs
  1706.  *
  1707.  *    -1 if expr is not a special variable
  1708.  *    0..3 if expr is "self", "true", "false", "nil", respectively.
  1709.  *    "super" is the same as self.
  1710.  */
  1711. static int isSpecialVariable(expr)
  1712. TreeNode expr;
  1713. {
  1714.   OOP        variable;
  1715.  
  1716.   if (expr->nodeType != variableNodeType) {
  1717.     return (-1);
  1718.   }
  1719.  
  1720.   variable = internString(expr->vList.name);
  1721.   if (variable == selfSymbol || variable == superSymbol) {
  1722.     return (receiverIndex);
  1723.   } else if (variable == trueSymbol) {
  1724.     return (trueIndex);
  1725.   } else if (variable == falseSymbol) {
  1726.     return (falseIndex);
  1727.   } else if (variable == nilSymbol) {
  1728.     return (nilIndex);
  1729.   } else {
  1730.     return (-1);
  1731.   }
  1732. }
  1733.  
  1734.  
  1735. /*
  1736.  *    static Boolean isSuper(expr)
  1737.  *
  1738.  * Description
  1739.  *
  1740.  *    Returns true if the expression passed to it represents the symbol
  1741.  *    "super"; false if not.
  1742.  *
  1743.  * Inputs
  1744.  *
  1745.  *    expr  : TreeNode that is an expression of some kind
  1746.  *
  1747.  * Outputs
  1748.  *
  1749.  *    true if "super" variable, false otherwise.
  1750.  */
  1751. static Boolean isSuper(expr)
  1752. TreeNode expr;
  1753. {
  1754.   if (expr->nodeType != variableNodeType) {
  1755.     return (false);
  1756.   }
  1757.  
  1758.   return (internString(expr->vList.name) == superSymbol);
  1759. }
  1760.  
  1761.  
  1762. /*
  1763.  *    static int addConstant(constExpr)
  1764.  *
  1765.  * Description
  1766.  *
  1767.  *    Scans the constants that are referenced by the current method.  If one
  1768.  *    is found that is equal to constExpr, the index of that constant is
  1769.  *    returned.  Otherwise, the constant is turned into a constant object,
  1770.  *    added to the constants of the method, and the new index is returned.
  1771.  *
  1772.  * Inputs
  1773.  *
  1774.  *    constExpr: 
  1775.  *        TreeNode of type constExprType, containing a literal constant
  1776.  *        of some kind.  Special cases -1, 0, 1, and 2 since they are
  1777.  *        available directly via instructions.
  1778.  *
  1779.  * Outputs
  1780.  *
  1781.  *    Index in the method's table of where this constant can be found,
  1782.  *    whether or not it was already there.  Returns a negative number if
  1783.  *    the constant is one of the above mentioned integers; in fact, the value
  1784.  *    returned is such that 3+returnValue is the numerical value.
  1785.  */
  1786. static int addConstant(constExpr)
  1787. TreeNode constExpr;
  1788. {
  1789.   int        i;
  1790.   long        intVal;
  1791.   OOP        constantOOP;
  1792.  
  1793.   for (i = 0; i < numLiterals; i++) {
  1794.     if (equalConstant(literalVec[i], constExpr)) {
  1795.       return (i);
  1796.     }
  1797.   }
  1798.  
  1799.   constantOOP = makeConstantOOP(constExpr);
  1800.   if (isInt(constantOOP)) {
  1801.     intVal = toInt(constantOOP);
  1802.     if (intVal >= -1 && intVal <= 2) {
  1803.       return ((int)(intVal - 3));
  1804.     }
  1805.   }
  1806.  
  1807.   return (addLiteral(constantOOP));
  1808. }
  1809.  
  1810. /*
  1811.  *    static Boolean equalConstant(oop, constExpr)
  1812.  *
  1813.  * Description
  1814.  *
  1815.  *    Returns true if "oop" and "constExpr" represent the same literal value.
  1816.  *    Primarily used by the compiler to store a single copy of duplicated
  1817.  *    literals in a method.  Can call itself in the case array literals.
  1818.  *
  1819.  * Inputs
  1820.  *
  1821.  *    oop   : An OOP that represents a constant value
  1822.  *    constExpr: 
  1823.  *        A piece of the syntax tree that represents a literal value.
  1824.  *
  1825.  * Outputs
  1826.  *
  1827.  *    True if "oop" and "constExpr" represent the same value; false
  1828.  *    otherwise. 
  1829.  */
  1830. static Boolean equalConstant(oop, constExpr)
  1831. OOP    oop;
  1832. TreeNode constExpr;
  1833. {
  1834.   TreeNode    arrayElt;
  1835.   int        len, i;
  1836.  
  1837.   /* ??? this kind of special casing of the elements of arrays bothers
  1838.      me...it should all be in one neat place. */
  1839.   if (constExpr->nodeType == symbolNodeType) { /* symbol in array constant */
  1840.     return (oop == constExpr->vExpr.selector);
  1841.   } else if (constExpr->nodeType == arrayEltListType) {
  1842.     if (isOOP(oop) && oopToObj(oop)->objClass == arrayClass) {
  1843.       for(len = 0, arrayElt = constExpr; arrayElt;
  1844.       len++, arrayElt = arrayElt->vList.next);
  1845.  
  1846.       if (len == numOOPs(oopToObj(oop))) {
  1847.     for (i = 1, arrayElt = constExpr; i <= len;
  1848.          i++, arrayElt = arrayElt->vList.next) {
  1849.       if (!equalConstant(arrayAt(oop, i), arrayElt->vList.value)) {
  1850.         return (false);
  1851.       }
  1852.     }
  1853.     return (true);
  1854.       }
  1855.     }
  1856.     return (false);
  1857.   }
  1858.  
  1859.  
  1860.  
  1861.   switch (constExpr->vConst.constType) {
  1862.   case intConst:
  1863.     if (oop == fromInt(constExpr->vConst.val.iVal)) {
  1864.       return (true);
  1865.     }
  1866.     break;
  1867.  
  1868.   case floatConst:
  1869.     if (isOOP(oop) && oopToObj(oop)->objClass == floatClass) {
  1870.       if (constExpr->vConst.val.fVal == floatOOPValue(oop)) {
  1871.     return (true);
  1872.       }
  1873.     }
  1874.     break;
  1875.  
  1876.   case charConst:
  1877.     if (oop == charOOPAt(constExpr->vConst.val.cVal)) {
  1878.       return (true);
  1879.     }
  1880.     break;
  1881.  
  1882.   case stringConst:
  1883.     if (isOOP(oop) && oopToObj(oop)->objClass == stringClass) {
  1884.       len = strlen(constExpr->vConst.val.sVal);
  1885.       if (len == stringOOPLen(oop)) {
  1886.     if (strncmp((char *)oopToObj(oop)->data, constExpr->vConst.val.sVal,
  1887.             len) == 0) {
  1888.       return (true);
  1889.     }
  1890.       }
  1891.     }
  1892.     break;
  1893.  
  1894.   case symbolConst:
  1895.     if (oop == constExpr->vConst.val.symVal) {
  1896.       return (true);
  1897.     }
  1898.     break;
  1899.     
  1900.   case arrayConst:
  1901.     if (isOOP(oop) && oopToObj(oop)->objClass == arrayClass) {
  1902.       /* ??? could keep the length in a counter */
  1903.       for(len = 0, arrayElt = constExpr->vConst.val.aVal; arrayElt;
  1904.       len++, arrayElt = arrayElt->vList.next);
  1905.       if (len == numOOPs(oopToObj(oop))) {
  1906.     for (i = 1, arrayElt = constExpr->vConst.val.aVal; i <= len;
  1907.          i++, arrayElt = arrayElt->vList.next) {
  1908.       if (!equalConstant(arrayAt(oop, i), arrayElt->vList.value)) {
  1909.         return (false);
  1910.       }
  1911.     }
  1912.     return (true);
  1913.       }
  1914.     }
  1915.     break;
  1916.   }
  1917.  
  1918.   return (false);
  1919. }
  1920.  
  1921. /*
  1922.  *    static OOP makeConstantOOP(constExpr)
  1923.  *
  1924.  * Description
  1925.  *
  1926.  *    Given a section of the syntax tree that represents a Smalltalk
  1927.  *    constant, this routine creates an OOP to be stored as a method literal
  1928.  *    in the method that's currently being compiled.
  1929.  *
  1930.  * Inputs
  1931.  *
  1932.  *    constExpr: 
  1933.  *        A portion of the tree that contains a constant value, including
  1934.  *        array constants.
  1935.  *
  1936.  * Outputs
  1937.  *
  1938.  *    An OOP that represents the constant's value.
  1939.  */
  1940. static OOP makeConstantOOP(constExpr)
  1941. TreeNode constExpr;
  1942. {
  1943.   TreeNode    arrayElt;
  1944.   int        len, i;
  1945.   OOP        resultOOP;
  1946.  
  1947.   if (constExpr->nodeType == symbolNodeType) { /* symbol in array constant */
  1948.     return (constExpr->vExpr.selector);
  1949.   } else if (constExpr->nodeType == arrayEltListType) {
  1950.     for(len = 0, arrayElt = constExpr; arrayElt;
  1951.     len++, arrayElt = arrayElt->vList.next);
  1952.     
  1953.     /* ??? this might be an uninitialized form of array creation for speed */
  1954.     resultOOP = arrayNew(len);
  1955.  
  1956.     for (i = 1, arrayElt = constExpr; i <= len;
  1957.      i++, arrayElt = arrayElt->vList.next) {
  1958.       arrayAtPut(resultOOP, i, makeConstantOOP(arrayElt->vList.value));
  1959.     }
  1960.     return (resultOOP);
  1961.   }
  1962.  
  1963.   switch (constExpr->vConst.constType) {
  1964.   case intConst:
  1965.     return (fromInt(constExpr->vConst.val.iVal));
  1966.  
  1967.   case floatConst:
  1968.     return (floatNew(constExpr->vConst.val.fVal));
  1969.  
  1970.   case charConst:
  1971.     return (charOOPAt(constExpr->vConst.val.cVal));
  1972.  
  1973.   case stringConst:
  1974.     return (stringNew(constExpr->vConst.val.sVal));
  1975.  
  1976.   case symbolConst:
  1977.     return (constExpr->vConst.val.symVal);
  1978.     
  1979.   case arrayConst:
  1980.     for(len = 0, arrayElt = constExpr->vConst.val.aVal; arrayElt;
  1981.     len++, arrayElt = arrayElt->vList.next);
  1982.     
  1983.     /* ??? this might be an uninitialized form of array creation for speed */
  1984.     resultOOP = arrayNew(len);
  1985.  
  1986.     for (i = 1, arrayElt = constExpr->vConst.val.aVal; i <= len;
  1987.      i++, arrayElt = arrayElt->vList.next) {
  1988.       arrayAtPut(resultOOP, i, makeConstantOOP(arrayElt->vList.value));
  1989.     }
  1990.     return (resultOOP);
  1991.   }
  1992.  
  1993.   return (nilOOP);
  1994. }
  1995.  
  1996. /*
  1997.  *    static int addSelector(selector)
  1998.  *
  1999.  * Description
  2000.  *
  2001.  *    Like addConstant, this routine adds "selector" to the set of selectors
  2002.  *    for the current method, and returns the index of that selector.  If the
  2003.  *    selector already existed, its index is returned.  If the selector is
  2004.  *    a special selector, then the negative of the bytecode that's associated
  2005.  *    with that special selector is returned.
  2006.  *
  2007.  * Inputs
  2008.  *
  2009.  *    selector: 
  2010.  *        A symbol that is the selector to be added to the selectors of
  2011.  *        the current method.
  2012.  *
  2013.  * Outputs
  2014.  *
  2015.  *    Index of the selector in the current method, or number < 0 which is
  2016.  *    the negative of the bytecode for a send special.
  2017.  */
  2018. static int addSelector(selector)
  2019. OOP    selector;
  2020. {
  2021.   int        builtin;
  2022.  
  2023.   if ((builtin = whichBuiltinSelector(selector)) != 0) {
  2024.     return (-builtin);
  2025.   } else {
  2026.     return (addForcedSelector(selector));
  2027.   }
  2028. }
  2029.  
  2030. /*
  2031.  *    static int whichBuiltinSelector(selector)
  2032.  *
  2033.  * Description
  2034.  *
  2035.  *    Looks for special-cased selectors, and returns a special number to
  2036.  *    indicate which selector was chosen.  If the selector isn't one of the
  2037.  *    special-cased ones, 0 is returned.
  2038.  *
  2039.  * Inputs
  2040.  *
  2041.  *    selector: 
  2042.  *        An instance of Symbol, to be special-cased.
  2043.  *
  2044.  * Outputs
  2045.  *
  2046.  *    0 if the selector isn't special-cased, otherwise an index to be used
  2047.  *    by the compiler for the selector.
  2048.  */
  2049. static int whichBuiltinSelector(selector)
  2050. OOP    selector;
  2051. {
  2052.   if (selector == atColonSymbol) {
  2053.     return (atColonSpecial);
  2054.   } else if (selector == atColonPutColonSymbol) {
  2055.     return (atColonPutColonSpecial);
  2056.   } else if (selector == sizeSymbol) {
  2057.     return (sizeSpecial);
  2058.   } else if (selector == nextSymbol) {
  2059.     return (nextSpecial);
  2060.   } else if (selector == nextPutColonSymbol) {
  2061.     return (nextPutColonSpecial);
  2062.   } else if (selector == atEndSymbol) {
  2063.     return (atEndSpecial);
  2064.   } else if (selector == classSymbol) {
  2065.     return (classSpecial);
  2066.   } else if (selector == blockCopyColonSymbol) {
  2067.     return (blockCopyColonSpecial);
  2068.   } else if (selector == valueSymbol) {
  2069.     return (valueSpecial);
  2070.   } else if (selector == valueColonSymbol) {
  2071.     return (valueColonSpecial);
  2072.   } else if (selector == doColonSymbol) {
  2073.     return (doColonSpecial);
  2074.   } else if (selector == newSymbol) {
  2075.     return (newSpecial);
  2076.   } else if (selector == newColonSymbol) {
  2077.     return (newColonSpecial);
  2078.   } else if (selector == plusSymbol) {
  2079.     return (plusSpecial);
  2080.   } else if (selector == minusSymbol) {
  2081.     return (minusSpecial);
  2082.   } else if (selector == lessThanSymbol) {
  2083.     return (lessThanSpecial);
  2084.   } else if (selector == greaterThanSymbol) {
  2085.     return (greaterThanSpecial);
  2086.   } else if (selector == lessEqualSymbol) {
  2087.     return (lessEqualSpecial);
  2088.   } else if (selector == greaterEqualSymbol) {
  2089.     return (greaterEqualSpecial);
  2090.   } else if (selector == equalSymbol) {
  2091.     return (equalSpecial);
  2092.   } else if (selector == notEqualSymbol) {
  2093.     return (notEqualSpecial);
  2094.   } else if (selector == timesSymbol) {
  2095.     return (timesSpecial);
  2096.   } else if (selector == divideSymbol) {
  2097.     return (divideSpecial);
  2098.   } else if (selector == remainderSymbol) {
  2099.     return (remainderSpecial);
  2100.   } else if (selector == bitShiftColonSymbol) {
  2101.     return (bitShiftColonSpecial);
  2102.   } else if (selector == integerDivideSymbol) {
  2103.     return (integerDivideSpecial);
  2104.   } else if (selector == bitAndColonSymbol) {
  2105.     return (bitAndColonSpecial);
  2106.   } else if (selector == bitOrColonSymbol) {
  2107.     return (bitOrColonSpecial);
  2108.   } else if (selector == sameObjectSymbol) {
  2109.     return (sameObjectSpecial);
  2110.   } else {
  2111.     return (0);
  2112.   }
  2113. }
  2114.  
  2115.  
  2116. /*
  2117.  *    static int addForcedSelector(selector)
  2118.  *
  2119.  * Description
  2120.  *
  2121.  *    Adds the given selector to the method literals, returning the index
  2122.  *    that the selector was stored under.
  2123.  *
  2124.  * Inputs
  2125.  *
  2126.  *    selector: 
  2127.  *        An instance of Symbol to be added.
  2128.  *
  2129.  * Outputs
  2130.  *
  2131.  *    Index of where in the literal vector the Symbol was stored.
  2132.  */
  2133. static int addForcedSelector(selector)     
  2134. OOP    selector;
  2135. {
  2136.  
  2137.   return (addForcedObject(selector));
  2138. }
  2139.  
  2140. /*
  2141.  *    int addForcedObject(oop)
  2142.  *
  2143.  * Description
  2144.  *
  2145.  *    Adds "oop" to the literal vector that's being created, unless it's
  2146.  *    already there.  "Already there" is defined as the exact same object is
  2147.  *    present in the literal vector.
  2148.  *
  2149.  * Inputs
  2150.  *
  2151.  *    oop   : An OOP to be added to the literal vector.
  2152.  *
  2153.  * Outputs
  2154.  *
  2155.  *    Index into the literal vector where the object was stored.  Seems like
  2156.  *    it's zero based, but I believe in practice that it's 1 based.
  2157.  */
  2158. int addForcedObject(oop)
  2159. OOP    oop;
  2160. {
  2161.   int        i;
  2162.  
  2163.   for (i = 0; i < numLiterals; i++) {
  2164.     if (literalVec[i] == oop) {
  2165.       return (i);
  2166.     }
  2167.   }
  2168.  
  2169.   return (addLiteral(oop));
  2170. }
  2171.  
  2172. /*
  2173.  *    static OOP computeSelector(selectorExpr)
  2174.  *
  2175.  * Description
  2176.  *
  2177.  *    Given a TreeNode of type keywordExprNode, this routine picks out the
  2178.  *    names selector "keywords", concatenates them, turns them into a symbol
  2179.  *    and returns that symbol.  This routine may also be called with a
  2180.  *    unaryExprType or binaryExprType tree node, in which case the selector
  2181.  *    is already known, so it is just returned.
  2182.  *
  2183.  * Inputs
  2184.  *
  2185.  *    selectorExpr:
  2186.  *        TreeNode node of type keywordExprNode, unaryExprType, or
  2187.  *        binaryExprType.
  2188.  *
  2189.  * Outputs
  2190.  *
  2191.  *    Symbol OOP that is the selector that "selectorExpr" represents.
  2192.  */
  2193. static OOP computeSelector(selectorExpr)
  2194. TreeNode selectorExpr;
  2195. {
  2196.   TreeNode    keyword;
  2197.   int        len;
  2198.   char        *nameBuf, *p;
  2199.  
  2200.   if (selectorExpr->nodeType == unaryExprType
  2201.       || selectorExpr->nodeType == binaryExprType) {
  2202.     return (selectorExpr->vExpr.selector);
  2203.   }
  2204.  
  2205.   len = 0;
  2206.   for (keyword = selectorExpr->vExpr.expression; keyword != nil;
  2207.        keyword = keyword->vList.next) {
  2208.     len += strlen(keyword->vList.name);
  2209.   }
  2210.  
  2211.   p = nameBuf = (char *)alloca(len+1);
  2212.   for (keyword = selectorExpr->vExpr.expression; keyword != nil;
  2213.        keyword = keyword->vList.next) {
  2214.     len = strlen(keyword->vList.name);
  2215.     strcpy(p, keyword->vList.name);
  2216.     p += len;
  2217.   }
  2218.  
  2219.   *p = '\0';
  2220.  
  2221.   return (internString(nameBuf));
  2222. }
  2223.  
  2224.  
  2225. /*
  2226.  *    static void addMethodClassVariable()
  2227.  *
  2228.  * Description
  2229.  *
  2230.  *    Called when a method contains at least one reference to super as a
  2231.  *    receiver, this routine makes sure that the last literal variable of the
  2232.  *    method is the class that the method is a part of.
  2233.  *
  2234.  */
  2235. static void addMethodClassVariable()
  2236. {
  2237.   addLiteral(associationNew(getClassSymbol(thisClass), thisClass));
  2238. }
  2239.  
  2240.  
  2241. /*
  2242.  *    initCompiler()
  2243.  *
  2244.  * Description
  2245.  *
  2246.  *    Prepares the compiler for execution.
  2247.  *
  2248.  */
  2249. initCompiler()
  2250. {
  2251.   hasExtendedSuper = false;
  2252.   initArgCount();
  2253.   initTempCount();
  2254.   initLiteralVec();
  2255.   initByteCodes();
  2256. }
  2257.  
  2258. /*
  2259.  *    static int listLength(listExpr)
  2260.  *
  2261.  * Description
  2262.  *
  2263.  *    Computes and returns the length of a parse tree list.
  2264.  *
  2265.  * Inputs
  2266.  *
  2267.  *    listExpr: 
  2268.  *        A list from the tree builder.
  2269.  *
  2270.  * Outputs
  2271.  *
  2272.  *    The length of the list, as an integer.
  2273.  */
  2274. static int listLength(listExpr)
  2275. TreeNode listExpr;
  2276. {
  2277.   TreeNode     l;
  2278.   long        len;
  2279.  
  2280.   for(len = 0, l = listExpr; l; l = l->vList.next, len++);
  2281.  
  2282.   if (sizeof(int) != 4) {
  2283.     if (len > (1L << (sizeof(int)*8 - 1))) {
  2284.       errorf("List too long, %ld", len);
  2285.       len = 1L << (sizeof(int)*8 - 1);
  2286.     }
  2287.   }
  2288.  
  2289.   return ((int)len);
  2290. }
  2291.  
  2292. /*
  2293.  *    static ByteCodes optimizeByteCodes(byteCodes)
  2294.  *
  2295.  * Description
  2296.  *
  2297.  *    Intended to scan the byte codes of a method, performing optimizations,
  2298.  *    and return a new vector of byte codes that represents the optimized
  2299.  *    byte code stream.  Currently a NOP.
  2300.  *
  2301.  * Inputs
  2302.  *
  2303.  *    byteCodes: 
  2304.  *        A vector of byte codes to be optimized.
  2305.  *
  2306.  * Outputs
  2307.  *
  2308.  *    Currently, the same byte codes that were passed in.
  2309.  */
  2310. static ByteCodes optimizeByteCodes(byteCodes)
  2311. ByteCodes byteCodes;
  2312. {
  2313.   /* ??? no optimization for now */
  2314.   return (byteCodes);
  2315. }
  2316.  
  2317.  
  2318. /***********************************************************************
  2319.  *
  2320.  *    Literal Vector manipulation routines.
  2321.  *
  2322.  ***********************************************************************/
  2323.  
  2324.  
  2325. /*
  2326.  *    static void initLiteralVec()
  2327.  *
  2328.  * Description
  2329.  *
  2330.  *    Prepares the literal vector for use.  The literal vector is where the
  2331.  *    compiler will store any literals that are used by the method being
  2332.  *    compiled.  The literal vector will grow as needed to accomodate the
  2333.  *    literals of the method.
  2334.  *
  2335.  */
  2336. static void initLiteralVec()
  2337. {
  2338.   numLiterals = 0;
  2339.  
  2340.   literalVecMax = LITERAL_VEC_CHUNK_SIZE;
  2341.   literalVec = (OOP *)malloc(LITERAL_VEC_CHUNK_SIZE*sizeof(OOP));
  2342. }
  2343.  
  2344. /*
  2345.  *    static int addLiteral(OOP)
  2346.  *
  2347.  * Description
  2348.  *
  2349.  *    Adds "OOP" to the literals associated with the method being compiled
  2350.  *    and returns the index of the literal slot that was used (1 based).
  2351.  *
  2352.  * Inputs
  2353.  *
  2354.  *    oop:    OOP to add to the literal vector.
  2355.  *
  2356.  * Outputs
  2357.  *
  2358.  *    Index (1 based) in the literal vector of where the OOP was added.
  2359.  */
  2360. static int addLiteral(oop)
  2361. OOP    oop;
  2362. {
  2363.   if (numLiterals >= literalVecMax) {
  2364.     reallocLiteralVec();
  2365.   }
  2366.  
  2367.   literalVec[numLiterals] = oop;
  2368.   return (numLiterals++);
  2369. }
  2370.  
  2371. /*
  2372.  *    static void reallocLiteralVec()
  2373.  *
  2374.  * Description
  2375.  *
  2376.  *    Called to grow the literal vector that the compiler is using.  Modifies
  2377.  *    the global variables "literalVec" and "literalVecMax" to reflect the
  2378.  *    growth. 
  2379.  *
  2380.  */
  2381. static void reallocLiteralVec()
  2382. {
  2383.   literalVecMax += LITERAL_VEC_CHUNK_SIZE;
  2384.   literalVec = (OOP *)realloc(literalVec, literalVecMax * sizeof(OOP));
  2385. }
  2386.  
  2387.  
  2388. /*
  2389.  *    OOP getMethodLiterals()
  2390.  *
  2391.  * Description
  2392.  *
  2393.  *    Creates a new array object that contains the literals for the method
  2394.  *    that's being compiled and returns it.  As a side effect, the currently
  2395.  *    allocated working literal vector is freed.  If there were no literals
  2396.  *    for the current method, nilOOP is returned.
  2397.  *
  2398.  * Outputs
  2399.  *
  2400.  *    The newly created array object, or nilOOP.
  2401.  */
  2402. static OOP getMethodLiterals()
  2403. {
  2404.   OOP        methodLiterals;
  2405.   int        i;
  2406.  
  2407.   if (numLiterals == 0) {
  2408.     return (nilOOP);
  2409.   }
  2410.  
  2411.   if (numLiterals > MAX_NUM_LITERALS) {
  2412.     errorf("Maximum number of literals, %d, exceeded: %d.  Extras ignored",
  2413.        MAX_NUM_LITERALS, numLiterals);
  2414.     numLiterals = MAX_NUM_LITERALS;
  2415.     hadError = true;
  2416.   }
  2417.  
  2418.   methodLiterals = arrayNew(numLiterals);
  2419.   for (i = 0; i < numLiterals; i++) {
  2420.     arrayAtPut(methodLiterals, i+1, literalVec[i]);
  2421.   }
  2422.  
  2423.   free(literalVec);
  2424.  
  2425.   return (methodLiterals);
  2426. }
  2427.  
  2428. /*
  2429.  *    static void installMethod(selector, primitiveIndex, numArgs, numTemps, literals, byteCodes)
  2430.  *
  2431.  * Description
  2432.  *
  2433.  *    Creates a new CompileMethod and installs it in the method dictionary
  2434.  *    for the current class.  If the current class does not contain a valid
  2435.  *    method dictionary, one is allocated for it.
  2436.  *
  2437.  * Inputs
  2438.  *
  2439.  *    selector: 
  2440.  *        A symbol that the compiled method should be stored under.  This
  2441.  *        selector is what will be matched against the message selector
  2442.  *        when a message is sent to the class that this method is a part
  2443.  *        of.
  2444.  *    primitiveIndex: 
  2445.  *        A C integer for the primitive operation associated with this
  2446.  *        method.  0 if no primitive is associated with this method.
  2447.  *    numArgs: 
  2448.  *        A C integer for the number of arguments that this method has.
  2449.  *    numTemps: 
  2450.  *        A C integer for the number of temporaries that this method has.
  2451.  *    literals: 
  2452.  *        An Array of method literals.
  2453.  *    byteCodes: 
  2454.  *        Vector of the bytecodes for the CompiledMethod.
  2455.  *
  2456.  */
  2457. static void installMethod(selector, primitiveIndex, numArgs, numTemps,
  2458.               literals, byteCodes)
  2459. OOP    selector, literals;
  2460. int    primitiveIndex, numArgs, numTemps;
  2461. ByteCodes byteCodes;
  2462. {
  2463.   OOP        method, methodDictionaryOOP;
  2464.  
  2465.   if (declareTracing) {
  2466.     printf("Class "); printObject(thisClass); printf("\n");
  2467.     printf("   "); printSymbol(selector); printf("\n");
  2468.   }
  2469.  
  2470.   methodDictionaryOOP = validClassMethodDictionary(thisClass);
  2471.   method = makeNewMethod(primitiveIndex, numArgs, numTemps, literals,
  2472.              byteCodes);
  2473.  
  2474.   identityDictionaryAtPut(methodDictionaryOOP, selector, method); 
  2475.   updateMethodCache(selector, thisClass, method);
  2476. }
  2477.  
  2478. /*
  2479.  *    static OOP makeNewMethod(primitiveIndex, numArgs, numTemps, literals, byteCodes)
  2480.  *
  2481.  * Description
  2482.  *
  2483.  *    Constructs and returns a new CompiledMethod instance.  It computes the
  2484.  *    method header based on its arguments, and on the contents of the
  2485.  *    method's byte codes.
  2486.  *
  2487.  * Inputs
  2488.  *
  2489.  *    primitiveIndex: 
  2490.  *        Integer, non-zero indicates that the method has a primitive
  2491.  *        method associated with it.  The primitive will be invoked first
  2492.  *        when the method is invoked, and only if the primitive signals
  2493.  *        failure will the remaining byte codes of the method be
  2494.  *        executed.
  2495.  *    numArgs: 
  2496.  *        Number of arguments that the method has.  A C integer.
  2497.  *    numTemps: 
  2498.  *        Number of temporaries that the method has. C integer.
  2499.  *    literals: 
  2500.  *        An Array of method literals that the CompiledMethod should use.
  2501.  *    byteCodes: 
  2502.  *        A vector of byte codes that make up the executable part of the
  2503.  *        method. 
  2504.  *
  2505.  * Outputs
  2506.  *
  2507.  *    A newly allocated CompiledMethod, fully initialized and ready to go.
  2508.  */
  2509. static OOP makeNewMethod(primitiveIndex, numArgs, numTemps, literals,
  2510.              byteCodes)
  2511. int    primitiveIndex, numArgs, numTemps;
  2512. OOP    literals;
  2513. ByteCodes byteCodes;
  2514. {
  2515.   MethodHeader    header;
  2516.   int        newFlags;
  2517.  
  2518.   header.intMark = 1;
  2519.   header.headerFlag = 0;
  2520.   if (primitiveIndex) {
  2521.     header.headerFlag = 3;
  2522.     if (declareTracing) {
  2523.       printf("  Primitive Index %d\n", primitiveIndex);
  2524.     }
  2525.   }
  2526.  
  2527.   header.primitiveIndex = primitiveIndex;
  2528.   header.numArgs = numArgs;
  2529.   header.numTemps = numTemps;
  2530.   header.numLiterals = numLiterals;
  2531.  
  2532.   if (primitiveIndex == 0) {
  2533.     if (numArgs == 0 && numTemps == 0
  2534.     && (newFlags = isSimpleReturn(byteCodes)) != 0) {
  2535.       header.headerFlag = newFlags & 0xFF;
  2536.       if (header.headerFlag == 2) {
  2537.     /* if returning an instance variable, this is indicated in the number
  2538.        of temporary variables */
  2539.     header.numTemps = newFlags >> 8;
  2540.       }
  2541.       freeByteCodes(byteCodes);
  2542.       byteCodes = nil;
  2543.       literals = nilOOP;
  2544.     }
  2545.   }
  2546.   return (methodNew(header, literals, byteCodes));
  2547. }
  2548.  
  2549. /*
  2550.  *    static OOP methodNew(header, literals, byteCodes)
  2551.  *
  2552.  * Description
  2553.  *
  2554.  *    Creates and returns a CompiledMethod.  The method is completely filled
  2555.  *    in, including the descriptor, the method literals, and the byte codes
  2556.  *    for the method.
  2557.  *
  2558.  * Inputs
  2559.  *
  2560.  *    header: Header of the method, a Smalltalk Integer.
  2561.  *    literals: 
  2562.  *        A Smalltalk Array of literals that the method should contain.
  2563.  *    byteCodes: 
  2564.  *        The byte code vector for the method.
  2565.  *
  2566.  * Outputs
  2567.  *
  2568.  *    A newly created CompiledMethod instance that's completely initialized.
  2569.  */
  2570. static OOP methodNew(header, literals, byteCodes)
  2571. MethodHeader header;
  2572. OOP    literals;
  2573. ByteCodes byteCodes;
  2574. {
  2575.   int        numByteCodes, numLiterals, i;
  2576.   CompiledMethod method;
  2577.   OOP        *oopPtr, litOOP, methodOOP;
  2578.  
  2579.   if (byteCodes != nil) {
  2580.     numByteCodes = byteCodeLength(byteCodes);
  2581.   } else {
  2582.     numByteCodes = 0;
  2583.   }
  2584.  
  2585.   method = simpleMethodNew(numByteCodes, header);
  2586.   method->descriptor = methodInfoNew();
  2587.   maybeMoveOOP(method->descriptor);
  2588.  
  2589.   numLiterals = header.numLiterals;
  2590.  
  2591.   for (i = 1; i <= numLiterals; i++) {
  2592.     litOOP = arrayAt(literals, i);
  2593.     maybeMoveOOP(litOOP);
  2594.     method->literals[i-1] = litOOP;
  2595.   }
  2596.  
  2597.   if (byteCodes != nil) {
  2598.     copyByteCodes((Byte *)&method->literals[numLiterals], byteCodes);
  2599.   }
  2600.  
  2601.   if (declareTracing) {
  2602.     printByteCodes(byteCodes, method->literals);
  2603.   }
  2604.  
  2605.   freeByteCodes(byteCodes);
  2606.  
  2607.   methodOOP = allocOOP(method);
  2608.   methodOOP->emptyBytes = (4 - numByteCodes) & 3;
  2609.   return (methodOOP);
  2610. }
  2611.  
  2612. /*
  2613.  *    OOP methodNewOOP(numByteCodes, header)
  2614.  *
  2615.  * Description
  2616.  *
  2617.  *    Used to implement the primitive that creates new compiled methods.
  2618.  *    Allocates and returns an OOP for a CompiledMethod.
  2619.  *
  2620.  * Inputs
  2621.  *
  2622.  *    numByteCodes: 
  2623.  *        Number of byte codes that the CompiledMethod will contain.
  2624.  *    header: The header for the CompiledMethod.  A Smalltalk integer.
  2625.  *
  2626.  * Outputs
  2627.  *
  2628.  *    Newly allocated CompiledMethod OOP.
  2629.  */
  2630. OOP methodNewOOP(numByteCodes, header)
  2631. long    numByteCodes;
  2632. MethodHeader header;
  2633. {
  2634.   CompiledMethod method;
  2635.   OOP        oop;
  2636.  
  2637.   method = simpleMethodNew(numByteCodes, header);
  2638.   oop = allocOOP(method);
  2639.   oop->emptyBytes = (4 - numByteCodes) & 3;
  2640.  
  2641.   return (oop);
  2642. }
  2643.  
  2644. /*
  2645.  *    static CompiledMethod simpleMethodNew(numByteCodes, header)
  2646.  *
  2647.  * Description
  2648.  *
  2649.  *    Creates and returns a compiled method object.  It sets the header of
  2650.  *    the compiled method from "header", and allocates the object so that it
  2651.  *    can hold "numByteCodes" byte codes.
  2652.  *
  2653.  * Inputs
  2654.  *
  2655.  *    numByteCodes: 
  2656.  *        An integer that is the number of byte codes the compiled method
  2657.  *        will contain.
  2658.  *    header: The method header to be used.  Used for placing into the
  2659.  *        compiled method and for figuring out how many literals the
  2660.  *        method has.
  2661.  *
  2662.  * Outputs
  2663.  *
  2664.  *    A compiled method object (NOT an OOP!).
  2665.  */
  2666. static CompiledMethod simpleMethodNew(numByteCodes, header)
  2667. long    numByteCodes;
  2668. MethodHeader header;
  2669. {
  2670.   CompiledMethod method;
  2671.   int        numBytes, numLiterals, i;
  2672.  
  2673.   numBytes = sizeof(struct CompiledMethodStruct) - sizeof(method->literals);
  2674.   numLiterals = 0;
  2675.  
  2676.   numLiterals = header.numLiterals;
  2677.   numBytes += numLiterals * sizeof(OOP);
  2678.  
  2679.   numBytes += numByteCodes;
  2680.  
  2681.   method = (CompiledMethod)allocObj(ROUNDED_WORDS(numBytes) << 2);
  2682.   method->objSize = ROUNDED_WORDS(numBytes);
  2683.   method->objClass = compiledMethodClass;
  2684.   method->header = header;
  2685.  
  2686.   return (method);
  2687. }
  2688.  
  2689. /*
  2690.  *    Boolean validMethodIndex(methodOOP, index)
  2691.  *
  2692.  * Description
  2693.  *
  2694.  *    Returns true if "index" is in the range of valid indices into the
  2695.  *    instance variables of CompiledMethod "methodOOP".
  2696.  *
  2697.  * Inputs
  2698.  *
  2699.  *    methodOOP: 
  2700.  *        An instance of CompiledMethod.
  2701.  *    index : 1 based integer index into the instance variables of the
  2702.  *        method.
  2703.  *
  2704.  * Outputs
  2705.  *
  2706.  *    True if "index" is within legal range of indices to the instance
  2707.  *    variables of the method.  False otherwise.
  2708.  */
  2709. Boolean validMethodIndex(methodOOP, index)
  2710. OOP    methodOOP;
  2711. long    index;
  2712. {
  2713.   CompiledMethod method;
  2714.  
  2715.   method = (CompiledMethod)oopToObj(methodOOP);
  2716.   /* Written this way to allow a debugging person to see the return value */
  2717.   /* The +2 counts for the description and header */
  2718.   if (index >= 1 && index <= method->header.numLiterals + 2) {
  2719.     return (true);
  2720.   } else {
  2721.     return (false);
  2722.   }
  2723. }
  2724.  
  2725. /*
  2726.  *    OOP compiledMethodAt(methodOOP, index)
  2727.  *
  2728.  * Description
  2729.  *
  2730.  *    Return the object at "index" in CompiledMethod "methodOOP".  Method
  2731.  *    literals currently start at index 3.
  2732.  *
  2733.  * Inputs
  2734.  *
  2735.  *    methodOOP: 
  2736.  *        An instance of CompiledMethod.
  2737.  *    index : A 1 based integer index into the instance variables of the
  2738.  *        method.  The method's descriptor is at index 1, and the method
  2739.  *        header is at index 2.
  2740.  *
  2741.  * Outputs
  2742.  *
  2743.  *    The object at the given index.
  2744.  */
  2745. OOP compiledMethodAt(methodOOP, index)
  2746. OOP    methodOOP;
  2747. long    index;
  2748. {
  2749.   CompiledMethod method;
  2750.   OOP        oop;
  2751.  
  2752.   method = (CompiledMethod)oopToObj(methodOOP);
  2753.   oop = method->literals[index-3]; /* index==1 => descriptor
  2754.                       => literals[index-2-1] */
  2755.   return (oop);
  2756. }
  2757.  
  2758. /*
  2759.  *    void compiledMethodAtPut(methodOOP, index, valueOOP)
  2760.  *
  2761.  * Description
  2762.  *
  2763.  *    Store "valueOOP" into the instance variable of CompiledMethod
  2764.  *    "methodOOP" at "index".
  2765.  *
  2766.  * Inputs
  2767.  *
  2768.  *    methodOOP: 
  2769.  *        A CompiledMethod instance.
  2770.  *    index : A 1 based index into the method's instance variables.  Method
  2771.  *        literals currently start at index 3; the descriptor is stored
  2772.  *        at index 1, and the header is at index 2.
  2773.  *    valueOOP: 
  2774.  *        The object to be stored at the given index.
  2775.  *
  2776.  */
  2777. void compiledMethodAtPut(methodOOP, index, valueOOP)
  2778. OOP    methodOOP, valueOOP;
  2779. long    index;
  2780. {
  2781.   CompiledMethod method;
  2782.   OOP        oop;
  2783.  
  2784.   method = (CompiledMethod)oopToObj(methodOOP);
  2785.   prepareToStore(methodOOP, valueOOP);
  2786.   method->literals[index-3] = valueOOP; /*index==1 => descriptor
  2787.                       => literals[index-2-1] */
  2788. }
  2789.  
  2790. /*
  2791.  *    OOP getMethodDescriptor(methodOOP)
  2792.  *
  2793.  * Description
  2794.  *
  2795.  *    Returns the descriptor for the given CompiledMethod.  The descriptor
  2796.  *    contains information about which category the method was stored under,
  2797.  *    and information that can be used to reconstruct the source code for the
  2798.  *    method.
  2799.  *
  2800.  * Inputs
  2801.  *
  2802.  *    methodOOP: 
  2803.  *        OOP of a CompiledMethod instance.
  2804.  *
  2805.  * Outputs
  2806.  *
  2807.  *    Descriptor that was stored in the method, normally a MethodInfo
  2808.  *    instance.
  2809.  */
  2810. OOP getMethodDescriptor(methodOOP)
  2811. OOP    methodOOP;
  2812. {
  2813.   CompiledMethod method;
  2814.  
  2815.   method = (CompiledMethod)oopToObj(methodOOP);
  2816.   return (method->descriptor);
  2817. }
  2818.  
  2819. /*
  2820.  *    void setMethodDescriptor(methodOOP, descriptorOOP)
  2821.  *
  2822.  * Description
  2823.  *
  2824.  *    Sets the method descriptor of "methodOOP" to be "descriptorOOP".
  2825.  *
  2826.  * Inputs
  2827.  *
  2828.  *    methodOOP: 
  2829.  *        OOP of a CompiledMethod.
  2830.  *    descriptorOOP: 
  2831.  *        OOP of a MethodInfo instance which contains the descriptor for
  2832.  *        the CompiledMethod. 
  2833.  *
  2834.  */
  2835. void setMethodDescriptor(methodOOP, descriptorOOP)
  2836. OOP    methodOOP, descriptorOOP;
  2837. {
  2838.   CompiledMethod method;
  2839.  
  2840.   method = (CompiledMethod)oopToObj(methodOOP);
  2841.   if (GCIsOn()) {
  2842.     prepareToStore(methodOOP, descriptorOOP);
  2843.   }
  2844.   method->descriptor = descriptorOOP;
  2845. }
  2846.  
  2847. /*
  2848.  *    static OOP methodInfoNew()
  2849.  *
  2850.  * Description
  2851.  *
  2852.  *    Returns an instance of MethodInfo.  This instance is used in the
  2853.  *    reconstruction of the source code for the method, and holds the
  2854.  *    category that the method belongs to.
  2855.  *
  2856.  * Outputs
  2857.  *
  2858.  *    Instance of MethodInfo used to hold category and source string
  2859.  *    information.
  2860.  */
  2861. static OOP methodInfoNew()
  2862. {
  2863.   MethodInfo    methodInfo;
  2864.  
  2865.   methodInfo = (MethodInfo)newInstance(methodInfoClass);
  2866.   methodInfo->sourceCode = fileSegmentNew();
  2867.   maybeMoveOOP(methodInfo->sourceCode);
  2868.   methodInfo->category = thisCategory;
  2869.  
  2870.   return (allocOOP(methodInfo));
  2871. }
  2872.  
  2873. /*
  2874.  *    static OOP fileSegmentNew()
  2875.  *
  2876.  * Description
  2877.  *
  2878.  *    Returns a FileSegment instance for the currently open compilation
  2879.  *    stream.   FileSegment instances are used record information useful in
  2880.  *    obtaining the source code for a method that's been compiled.  Depending
  2881.  *    on whether the input stream is a string or a FileStream, the instance
  2882.  *    variables are different; for a string, the entire contents of the
  2883.  *    string is preserved as the source code for the method; for a disk file,
  2884.  *    the file name, byte offset and length are preserved.
  2885.  *
  2886.  * Outputs
  2887.  *
  2888.  *    A FileSegment instance that can be used to recover the current method's
  2889.  *    source code.
  2890.  */
  2891. static OOP fileSegmentNew()
  2892. {
  2893.   OOP        fileName, stringContents;
  2894.   FileSegment    fileSegment;
  2895.   int        startPos;
  2896.  
  2897.   switch (getCurStreamType()) {
  2898.   case unknownStreamType:
  2899.     return (nilOOP);
  2900.  
  2901.   case fileStreamType: 
  2902.     fileName = getCurFileName();
  2903.     fileSegment = (FileSegment)newInstance(fileSegmentClass);
  2904.     maybeMoveOOP(fileName);
  2905.     fileSegment->fileName = fileName;
  2906.     startPos = getMethodStartPos();
  2907.     fileSegment->startPos = fromInt(startPos);
  2908.     /* The second -1 removes the terminating '!' */
  2909.     fileSegment->length = fromInt(getCurFilePos() - startPos - 1 - 1);
  2910.     return (allocOOP(fileSegment));
  2911.  
  2912.   case stringStreamType:
  2913.     stringContents = getCurString();
  2914.     return (stringContents);
  2915.  
  2916. #ifdef USE_READLINE
  2917.   case readlineStreamType:
  2918.     stringContents = getCurReadline();
  2919.     return (stringContents);
  2920. #endif /* USE_READLINE */
  2921.   }
  2922. }
  2923.